diff --git a/SimpleWebXR-Demo/Assets/SimpleWebXR/Examples/Scenes/HitTestExample.unity b/SimpleWebXR-Demo/Assets/SimpleWebXR/Examples/Scenes/HitTestExample.unity
new file mode 100644
index 0000000..b44faef
--- /dev/null
+++ b/SimpleWebXR-Demo/Assets/SimpleWebXR/Examples/Scenes/HitTestExample.unity
@@ -0,0 +1,713 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!29 &1
+OcclusionCullingSettings:
+ m_ObjectHideFlags: 0
+ serializedVersion: 2
+ m_OcclusionBakeSettings:
+ smallestOccluder: 5
+ smallestHole: 0.25
+ backfaceThreshold: 100
+ m_SceneGUID: 00000000000000000000000000000000
+ m_OcclusionCullingData: {fileID: 0}
+--- !u!104 &2
+RenderSettings:
+ m_ObjectHideFlags: 0
+ serializedVersion: 9
+ m_Fog: 0
+ m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
+ m_FogMode: 3
+ m_FogDensity: 0.01
+ m_LinearFogStart: 0
+ m_LinearFogEnd: 300
+ m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
+ m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
+ m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
+ m_AmbientIntensity: 1
+ m_AmbientMode: 0
+ m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
+ m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
+ m_HaloStrength: 0.5
+ m_FlareStrength: 1
+ m_FlareFadeSpeed: 3
+ m_HaloTexture: {fileID: 0}
+ m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
+ m_DefaultReflectionMode: 0
+ m_DefaultReflectionResolution: 128
+ m_ReflectionBounces: 1
+ m_ReflectionIntensity: 1
+ m_CustomReflection: {fileID: 0}
+ m_Sun: {fileID: 0}
+ m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1}
+ m_UseRadianceAmbientProbe: 0
+--- !u!157 &3
+LightmapSettings:
+ m_ObjectHideFlags: 0
+ serializedVersion: 11
+ m_GIWorkflowMode: 0
+ m_GISettings:
+ serializedVersion: 2
+ m_BounceScale: 1
+ m_IndirectOutputScale: 1
+ m_AlbedoBoost: 1
+ m_EnvironmentLightingMode: 0
+ m_EnableBakedLightmaps: 1
+ m_EnableRealtimeLightmaps: 1
+ m_LightmapEditorSettings:
+ serializedVersion: 12
+ m_Resolution: 2
+ m_BakeResolution: 40
+ m_AtlasSize: 1024
+ m_AO: 0
+ m_AOMaxDistance: 1
+ m_CompAOExponent: 1
+ m_CompAOExponentDirect: 0
+ m_ExtractAmbientOcclusion: 0
+ m_Padding: 2
+ m_LightmapParameters: {fileID: 0}
+ m_LightmapsBakeMode: 1
+ m_TextureCompression: 1
+ m_FinalGather: 0
+ m_FinalGatherFiltering: 1
+ m_FinalGatherRayCount: 256
+ m_ReflectionCompression: 2
+ m_MixedBakeMode: 2
+ m_BakeBackend: 1
+ m_PVRSampling: 1
+ m_PVRDirectSampleCount: 32
+ m_PVRSampleCount: 500
+ m_PVRBounces: 2
+ m_PVREnvironmentSampleCount: 500
+ m_PVREnvironmentReferencePointCount: 2048
+ m_PVRFilteringMode: 2
+ m_PVRDenoiserTypeDirect: 0
+ m_PVRDenoiserTypeIndirect: 0
+ m_PVRDenoiserTypeAO: 0
+ m_PVRFilterTypeDirect: 0
+ m_PVRFilterTypeIndirect: 0
+ m_PVRFilterTypeAO: 0
+ m_PVREnvironmentMIS: 0
+ m_PVRCulling: 1
+ m_PVRFilteringGaussRadiusDirect: 1
+ m_PVRFilteringGaussRadiusIndirect: 5
+ m_PVRFilteringGaussRadiusAO: 2
+ m_PVRFilteringAtrousPositionSigmaDirect: 0.5
+ m_PVRFilteringAtrousPositionSigmaIndirect: 2
+ m_PVRFilteringAtrousPositionSigmaAO: 1
+ m_ExportTrainingData: 0
+ m_TrainingDataDestination: TrainingData
+ m_LightProbeSampleCountMultiplier: 4
+ m_LightingDataAsset: {fileID: 0}
+ m_UseShadowmask: 1
+--- !u!196 &4
+NavMeshSettings:
+ serializedVersion: 2
+ m_ObjectHideFlags: 0
+ m_BuildSettings:
+ serializedVersion: 2
+ agentTypeID: 0
+ agentRadius: 0.5
+ agentHeight: 2
+ agentSlope: 45
+ agentClimb: 0.4
+ ledgeDropHeight: 0
+ maxJumpAcrossDistance: 0
+ minRegionArea: 2
+ manualCellSize: 0
+ cellSize: 0.16666667
+ manualTileSize: 0
+ tileSize: 256
+ accuratePlacement: 0
+ debug:
+ m_Flags: 0
+ m_NavMeshData: {fileID: 0}
+--- !u!1 &508041732
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 508041736}
+ - component: {fileID: 508041735}
+ - component: {fileID: 508041734}
+ - component: {fileID: 508041733}
+ m_Layer: 0
+ m_Name: Reticle
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!136 &508041733
+CapsuleCollider:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 508041732}
+ m_Material: {fileID: 0}
+ m_IsTrigger: 0
+ m_Enabled: 1
+ m_Radius: 0.5000001
+ m_Height: 2
+ m_Direction: 1
+ m_Center: {x: 0.000000059604645, y: 0, z: -0.00000008940697}
+--- !u!23 &508041734
+MeshRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 508041732}
+ m_Enabled: 1
+ m_CastShadows: 1
+ m_ReceiveShadows: 1
+ m_DynamicOccludee: 1
+ m_MotionVectors: 1
+ m_LightProbeUsage: 1
+ m_ReflectionProbeUsage: 1
+ m_RayTracingMode: 2
+ m_RenderingLayerMask: 1
+ m_RendererPriority: 0
+ m_Materials:
+ - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0}
+ m_StaticBatchInfo:
+ firstSubMesh: 0
+ subMeshCount: 0
+ m_StaticBatchRoot: {fileID: 0}
+ m_ProbeAnchor: {fileID: 0}
+ m_LightProbeVolumeOverride: {fileID: 0}
+ m_ScaleInLightmap: 1
+ m_ReceiveGI: 1
+ m_PreserveUVs: 0
+ m_IgnoreNormalsForChartDetection: 0
+ m_ImportantGI: 0
+ m_StitchLightmapSeams: 1
+ m_SelectedEditorRenderState: 3
+ m_MinimumChartSize: 4
+ m_AutoUVMaxDistance: 0.5
+ m_AutoUVMaxAngle: 89
+ m_LightmapParameters: {fileID: 0}
+ m_SortingLayerID: 0
+ m_SortingLayer: 0
+ m_SortingOrder: 0
+--- !u!33 &508041735
+MeshFilter:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 508041732}
+ m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0}
+--- !u!4 &508041736
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 508041732}
+ m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 0.1, y: 0.01, z: 0.1}
+ m_Children: []
+ m_Father: {fileID: 0}
+ m_RootOrder: 3
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!1 &886035885
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 886035888}
+ - component: {fileID: 886035887}
+ - component: {fileID: 886035886}
+ m_Layer: 0
+ m_Name: EventSystem
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!114 &886035886
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 886035885}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_HorizontalAxis: Horizontal
+ m_VerticalAxis: Vertical
+ m_SubmitButton: Submit
+ m_CancelButton: Cancel
+ m_InputActionsPerSecond: 10
+ m_RepeatDelay: 0.5
+ m_ForceModuleActive: 0
+--- !u!114 &886035887
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 886035885}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_FirstSelected: {fileID: 0}
+ m_sendNavigationEvents: 1
+ m_DragThreshold: 10
+--- !u!4 &886035888
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 886035885}
+ m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_Children: []
+ m_Father: {fileID: 0}
+ m_RootOrder: 4
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!1 &1044331785
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 1044331789}
+ - component: {fileID: 1044331788}
+ - component: {fileID: 1044331787}
+ - component: {fileID: 1044331786}
+ m_Layer: 5
+ m_Name: Canvas
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!114 &1044331786
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1044331785}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_IgnoreReversedGraphics: 1
+ m_BlockingObjects: 0
+ m_BlockingMask:
+ serializedVersion: 2
+ m_Bits: 4294967295
+--- !u!114 &1044331787
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1044331785}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_UiScaleMode: 0
+ m_ReferencePixelsPerUnit: 100
+ m_ScaleFactor: 1
+ m_ReferenceResolution: {x: 800, y: 600}
+ m_ScreenMatchMode: 0
+ m_MatchWidthOrHeight: 0
+ m_PhysicalUnit: 3
+ m_FallbackScreenDPI: 96
+ m_DefaultSpriteDPI: 96
+ m_DynamicPixelsPerUnit: 1
+--- !u!223 &1044331788
+Canvas:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1044331785}
+ m_Enabled: 1
+ serializedVersion: 3
+ m_RenderMode: 0
+ m_Camera: {fileID: 0}
+ m_PlaneDistance: 100
+ m_PixelPerfect: 0
+ m_ReceivesEvents: 1
+ m_OverrideSorting: 0
+ m_OverridePixelPerfect: 0
+ m_SortingBucketNormalizedSize: 0
+ m_AdditionalShaderChannelsFlag: 0
+ m_SortingLayerID: 0
+ m_SortingOrder: 0
+ m_TargetDisplay: 0
+--- !u!224 &1044331789
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1044331785}
+ m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 0, y: 0, z: 0}
+ m_Children:
+ - {fileID: 1226760882}
+ m_Father: {fileID: 0}
+ m_RootOrder: 5
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0, y: 0}
+ m_AnchorMax: {x: 0, y: 0}
+ m_AnchoredPosition: {x: 0, y: 0}
+ m_SizeDelta: {x: 0, y: 0}
+ m_Pivot: {x: 0, y: 0}
+--- !u!1 &1226760881
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 1226760882}
+ - component: {fileID: 1226760884}
+ - component: {fileID: 1226760883}
+ m_Layer: 5
+ m_Name: Text
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &1226760882
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1226760881}
+ m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_Children: []
+ m_Father: {fileID: 1044331789}
+ m_RootOrder: 0
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0.5, y: 0.5}
+ m_AnchorMax: {x: 0.5, y: 0.5}
+ m_AnchoredPosition: {x: 0, y: 0}
+ m_SizeDelta: {x: 500, y: 300}
+ m_Pivot: {x: 0.5, y: 0.5}
+--- !u!114 &1226760883
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1226760881}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Material: {fileID: 0}
+ m_Color: {r: 1, g: 0, b: 0.1605196, a: 1}
+ m_RaycastTarget: 0
+ m_Maskable: 0
+ m_OnCullStateChanged:
+ m_PersistentCalls:
+ m_Calls: []
+ m_FontData:
+ m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
+ m_FontSize: 14
+ m_FontStyle: 0
+ m_BestFit: 0
+ m_MinSize: 10
+ m_MaxSize: 40
+ m_Alignment: 4
+ m_AlignByGeometry: 0
+ m_RichText: 1
+ m_HorizontalOverflow: 0
+ m_VerticalOverflow: 0
+ m_LineSpacing: 1
+ m_Text: 'You should start an immersive session to try this example.
+
+ You device
+ should support Hit Test WebXR features.
+
+
+ The reticle below should move and
+ interact with the real world around you.'
+--- !u!222 &1226760884
+CanvasRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1226760881}
+ m_CullTransparentMesh: 0
+--- !u!1 &1902347869
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 1902347871}
+ - component: {fileID: 1902347870}
+ - component: {fileID: 1902347872}
+ m_Layer: 0
+ m_Name: WebXR
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!114 &1902347870
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1902347869}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: b5f1dbbdfef877f4ba9074a75fb308be, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ HideStartButton: 0
+ ReferenceSpace: 0
+ FallbackUserHeight: 1.8
+--- !u!4 &1902347871
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1902347869}
+ m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_Children: []
+ m_Father: {fileID: 0}
+ m_RootOrder: 2
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &1902347872
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1902347869}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: eb6027ab8221b7648aec7d0146dfd713, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ Reticle: {fileID: 508041732}
+ Text: {fileID: 1226760883}
+--- !u!1 &2040428756
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 2040428758}
+ - component: {fileID: 2040428757}
+ m_Layer: 0
+ m_Name: Directional Light
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!108 &2040428757
+Light:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 2040428756}
+ m_Enabled: 1
+ serializedVersion: 10
+ m_Type: 1
+ m_Shape: 0
+ m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1}
+ m_Intensity: 1
+ m_Range: 10
+ m_SpotAngle: 30
+ m_InnerSpotAngle: 21.80208
+ m_CookieSize: 10
+ m_Shadows:
+ m_Type: 0
+ m_Resolution: -1
+ m_CustomResolution: -1
+ m_Strength: 1
+ m_Bias: 0.05
+ m_NormalBias: 0.4
+ m_NearPlane: 0.2
+ m_CullingMatrixOverride:
+ e00: 1
+ e01: 0
+ e02: 0
+ e03: 0
+ e10: 0
+ e11: 1
+ e12: 0
+ e13: 0
+ e20: 0
+ e21: 0
+ e22: 1
+ e23: 0
+ e30: 0
+ e31: 0
+ e32: 0
+ e33: 1
+ m_UseCullingMatrixOverride: 0
+ m_Cookie: {fileID: 0}
+ m_DrawHalo: 0
+ m_Flare: {fileID: 0}
+ m_RenderMode: 0
+ m_CullingMask:
+ serializedVersion: 2
+ m_Bits: 4294967295
+ m_RenderingLayerMask: 1
+ m_Lightmapping: 4
+ m_LightShadowCasterMode: 0
+ m_AreaSize: {x: 1, y: 1}
+ m_BounceIntensity: 1
+ m_ColorTemperature: 6570
+ m_UseColorTemperature: 0
+ m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0}
+ m_UseBoundingSphereOverride: 0
+ m_ShadowRadius: 0
+ m_ShadowAngle: 0
+--- !u!4 &2040428758
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 2040428756}
+ m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261}
+ m_LocalPosition: {x: 0, y: 3, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_Children: []
+ m_Father: {fileID: 0}
+ m_RootOrder: 1
+ m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0}
+--- !u!1 &2057464190
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 2057464193}
+ - component: {fileID: 2057464192}
+ - component: {fileID: 2057464191}
+ - component: {fileID: 2057464194}
+ m_Layer: 0
+ m_Name: Main Camera
+ m_TagString: MainCamera
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!81 &2057464191
+AudioListener:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 2057464190}
+ m_Enabled: 1
+--- !u!20 &2057464192
+Camera:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 2057464190}
+ m_Enabled: 1
+ serializedVersion: 2
+ m_ClearFlags: 1
+ m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
+ m_projectionMatrixMode: 1
+ m_GateFitMode: 2
+ m_FOVAxisMode: 0
+ m_SensorSize: {x: 36, y: 24}
+ m_LensShift: {x: 0, y: 0}
+ m_FocalLength: 50
+ m_NormalizedViewPortRect:
+ serializedVersion: 2
+ x: 0
+ y: 0
+ width: 1
+ height: 1
+ near clip plane: 0.3
+ far clip plane: 1000
+ field of view: 60
+ orthographic: 0
+ orthographic size: 5
+ m_Depth: -1
+ m_CullingMask:
+ serializedVersion: 2
+ m_Bits: 4294967295
+ m_RenderingPath: -1
+ m_TargetTexture: {fileID: 0}
+ m_TargetDisplay: 0
+ m_TargetEye: 3
+ m_HDR: 1
+ m_AllowMSAA: 1
+ m_AllowDynamicResolution: 0
+ m_ForceIntoRT: 0
+ m_OcclusionCulling: 1
+ m_StereoConvergence: 10
+ m_StereoSeparation: 0.022
+--- !u!4 &2057464193
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 2057464190}
+ m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+ m_LocalPosition: {x: 0, y: 1, z: -10}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_Children: []
+ m_Father: {fileID: 0}
+ m_RootOrder: 0
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!45 &2057464194
+Skybox:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 2057464190}
+ m_Enabled: 1
+ m_CustomSkybox: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
diff --git a/SimpleWebXR-Demo/Assets/SimpleWebXR/Examples/Scenes/HitTestExample.unity.meta b/SimpleWebXR-Demo/Assets/SimpleWebXR/Examples/Scenes/HitTestExample.unity.meta
new file mode 100644
index 0000000..a3e68b5
--- /dev/null
+++ b/SimpleWebXR-Demo/Assets/SimpleWebXR/Examples/Scenes/HitTestExample.unity.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 2ca6c05b6d4c7684aa7f02a113890db3
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/SimpleWebXR-Demo/Assets/SimpleWebXR/Examples/Scripts/HitTestExample.meta b/SimpleWebXR-Demo/Assets/SimpleWebXR/Examples/Scripts/HitTestExample.meta
new file mode 100644
index 0000000..712b338
--- /dev/null
+++ b/SimpleWebXR-Demo/Assets/SimpleWebXR/Examples/Scripts/HitTestExample.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 69a3ffeef1afec44ba7f4eb9d806b005
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/SimpleWebXR-Demo/Assets/SimpleWebXR/Examples/Scripts/HitTestExample/HitTestExample.cs b/SimpleWebXR-Demo/Assets/SimpleWebXR/Examples/Scripts/HitTestExample/HitTestExample.cs
new file mode 100644
index 0000000..3bac3f9
--- /dev/null
+++ b/SimpleWebXR-Demo/Assets/SimpleWebXR/Examples/Scripts/HitTestExample/HitTestExample.cs
@@ -0,0 +1,37 @@
+using Rufus31415.WebXR;
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.UI;
+
+public class HitTestExample : MonoBehaviour
+{
+ public GameObject Reticle;
+
+ public Text Text;
+
+ // Start is called before the first frame update
+ void Start()
+ {
+ SimpleWebXR.SessionStart.AddListener(SimpleWebXR.HitTestStart);
+ }
+
+ // Update is called once per frame
+ void Update()
+ {
+ if (!SimpleWebXR.InSession || !Reticle) return;
+
+ if (!SimpleWebXR.HitTestInProgress)
+ {
+ Text.text = "Hit test failed\r\n\r\n" + (SimpleWebXR.HitTestSupported ? "Your device supports hit test" : "Your device doesn't support hit test");
+ }
+ else
+ {
+ Text.text = "Hit test in progress at :\r\n x : " + SimpleWebXR.HitTestPosition.x + "\r\n y : " + SimpleWebXR.HitTestPosition.y + "\r\n z : " + SimpleWebXR.HitTestPosition.z;
+
+
+ Reticle.transform.position = SimpleWebXR.HitTestPosition;
+ Reticle.transform.rotation = SimpleWebXR.HitTestRotation;
+ }
+ }
+}
diff --git a/SimpleWebXR-Demo/Assets/SimpleWebXR/Examples/Scripts/HitTestExample/HitTestExample.cs.meta b/SimpleWebXR-Demo/Assets/SimpleWebXR/Examples/Scripts/HitTestExample/HitTestExample.cs.meta
new file mode 100644
index 0000000..6c26b22
--- /dev/null
+++ b/SimpleWebXR-Demo/Assets/SimpleWebXR/Examples/Scripts/HitTestExample/HitTestExample.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: eb6027ab8221b7648aec7d0146dfd713
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.rufus31415.simplewebxr/Runtime/Plugins/WebGL/SimpleWebXR.jslib b/com.rufus31415.simplewebxr/Runtime/Plugins/WebGL/SimpleWebXR.jslib
index d414454..1e30bb9 100644
--- a/com.rufus31415.simplewebxr/Runtime/Plugins/WebGL/SimpleWebXR.jslib
+++ b/com.rufus31415.simplewebxr/Runtime/Plugins/WebGL/SimpleWebXR.jslib
@@ -116,6 +116,9 @@ mergeInto(LibraryManager.library, {
// start y position that is substract to all y position so that start y is forced to 0
_yOffset = 0;
+ // initialize hit test source variable
+ _xrHitTestSource = null;
+
// copy camera data in shared buffer
_dataArraySetView = function (view, id) {
var floatStartId = id * 27;
@@ -287,10 +290,10 @@ mergeInto(LibraryManager.library, {
var quaternion = new Float32Array(4);
- quaternion[3] = Math.sqrt(Math.max(0, 1 + poses[jointIndex + 0] + poses[jointIndex + 5] + poses[jointIndex + 10])) / 2;
- quaternion[0] = Math.sqrt(Math.max(0, 1 + poses[jointIndex + 0] - poses[jointIndex + 5] - poses[jointIndex + 10])) / 2;
- quaternion[1] = Math.sqrt(Math.max(0, 1 - poses[jointIndex + 0] + poses[jointIndex + 5] - poses[jointIndex + 10])) / 2;
- quaternion[2] = Math.sqrt(Math.max(0, 1 - poses[jointIndex + 0] - poses[jointIndex + 5] + poses[jointIndex + 10])) / 2;
+ quaternion[3] = Math.sqrt(Math.max(0, 1 + poses[jointIndex] + poses[jointIndex + 5] + poses[jointIndex + 10])) / 2;
+ quaternion[0] = Math.sqrt(Math.max(0, 1 + poses[jointIndex] - poses[jointIndex + 5] - poses[jointIndex + 10])) / 2;
+ quaternion[1] = Math.sqrt(Math.max(0, 1 - poses[jointIndex] + poses[jointIndex + 5] - poses[jointIndex + 10])) / 2;
+ quaternion[2] = Math.sqrt(Math.max(0, 1 - poses[jointIndex] - poses[jointIndex + 5] + poses[jointIndex + 10])) / 2;
quaternion[0] *= Math.sign(quaternion[0] * (poses[jointIndex + 6] - poses[jointIndex + 9]));
quaternion[1] *= Math.sign(quaternion[1] * (poses[jointIndex + 8] - poses[jointIndex + 2]));
quaternion[2] *= Math.sign(quaternion[2] * (poses[jointIndex + 1] - poses[jointIndex + 4]));
@@ -418,6 +421,34 @@ mergeInto(LibraryManager.library, {
_byteArray[44] = hasLeftInput;
_byteArray[45] = hasRightInput;
+ // handle hit test
+ if (_xrHitTestSource) {
+ var hitTestResults = frame.getHitTestResults(_xrHitTestSource);
+ if (hitTestResults.length > 0) {
+ var delta = (_useLocalSpaceForInput ? 0 : _dataArray[100]);
+
+ var refSpace = _useLocalSpaceForInput ? _arSession.localSpace : _arSession.localFloorSpace;
+
+ var pose = hitTestResults[0].getPose(refSpace);
+
+ _byteArray[48] = 1; // hit test in progress
+
+ _dataArray[105] = pose.transform.position.x;
+ _dataArray[106] = pose.transform.position.y - delta - _yOffset;
+ _dataArray[107] = pose.transform.position.z;
+ _dataArray[108] = pose.transform.orientation.x;
+ _dataArray[109] = pose.transform.orientation.y;
+ _dataArray[110] = pose.transform.orientation.z;
+ _dataArray[111] = pose.transform.orientation.w;
+ }
+ else {
+ _byteArray[48] = 0;
+ }
+ }
+ else {
+ _byteArray[48] = 0;
+ }
+
_firstFrame = false;
}
@@ -552,6 +583,14 @@ mergeInto(LibraryManager.library, {
GLctx.canvas.width = glLayer.framebufferWidth;
GLctx.canvas.height = glLayer.framebufferHeight;
+ // Test if hit test is supported
+ if (typeof session.requestHitTestSource === "function") {
+ _byteArray[49] = 1;
+ }
+ else {
+ _byteArray[49] = 0;
+ }
+
// get working reference space
session.requestReferenceSpace('local-floor').then(function (space) {
_arSession.localFloorSpace = space;
@@ -571,6 +610,36 @@ mergeInto(LibraryManager.library, {
if (_arSession) _arSession.end();
},
+ /****************************************************************************/
+ // Starts hit test
+ InternalHitTestStart: function () {
+ if (_arSession) {
+ if (typeof _arSession.requestHitTestSource === "function") {
+ _byteArray[49] = 1;
+
+ if (!_xrHitTestSource) { // if hit test is not still in progress
+ _arSession.requestReferenceSpace('viewer').then(function (refSpace) {
+ _arSession.requestHitTestSource({ space: refSpace }).then(function (hitTestSource) {
+ _xrHitTestSource = hitTestSource;
+ });
+ });
+ }
+ }
+ else {
+ _byteArray[49] = 0;
+ }
+ }
+ },
+
+ /****************************************************************************/
+ // Ends hit test
+ InternalHitTestCancel: function () {
+ if (_arSession && _xrHitTestSource) {
+ _xrHitTestSource.cancel();
+ _xrHitTestSource = null;
+ }
+ },
+
/****************************************************************************/
// Poll device orientation
InternalGetDeviceOrientation: function (orientationArray, orientationInfo) {
diff --git a/com.rufus31415.simplewebxr/Runtime/Scripts/SimpleWebXR.cs b/com.rufus31415.simplewebxr/Runtime/Scripts/SimpleWebXR.cs
index bab8b5a..82a46d8 100644
--- a/com.rufus31415.simplewebxr/Runtime/Scripts/SimpleWebXR.cs
+++ b/com.rufus31415.simplewebxr/Runtime/Scripts/SimpleWebXR.cs
@@ -225,6 +225,27 @@ private void OnGUI()
///
public static Camera RightEye => _cameras[1];
+ ///
+ /// Indicates that a hit test is available in HitTestPosition and HitTestRotation
+ ///
+ public static bool HitTestInProgress => _byteArray[48] != 0;
+
+ ///
+ /// Indicates hit test is supported
+ /// The immersive session should be started to estimate this capability
+ ///
+ public static bool HitTestSupported => _byteArray[49] != 0;
+
+ ///
+ /// Position of the hit test between head ray and the real world
+ ///
+ public static Vector3 HitTestPosition;
+
+ ///
+ /// Orientation of the hit test normale between head ray and the real world
+ ///
+ public static Quaternion HitTestRotation;
+
///
/// Initialize the binding with the WebXR API, via shared arrays
///
@@ -307,9 +328,28 @@ public static void StartSession()
public static void EndSession()
{
if (!InternalInSession) return;
+ InternalHitTestCancel();
InternalEndSession();
}
+ ///
+ /// Starts hit test
+ ///
+ public static void HitTestStart()
+ {
+ Initialize();
+ InternalHitTestStart();
+ }
+
+ ///
+ /// Ends hit test
+ ///
+ public static void HitTestCancel()
+ {
+ Initialize();
+ InternalHitTestCancel();
+ }
+
///
/// Update cameras (eyes), input sources and propagates WebXR events to Unity. This function should be called once per frame.
///
@@ -331,6 +371,8 @@ public static void UpdateWebXR()
_byteArray[3] = 0;
}
+ UpdateHitTest();
+
// Session state changed invoked when all gamepads and cameras are updated
if (InternalInSession && !InSession) //New session detected
{
@@ -406,7 +448,8 @@ public static string Stringify()
// [102] : right input haptic pulse value
// [103] : left input haptic pulse duration
// [104] : right input haptic pulse duration
- private static readonly float[] _dataArray = new float[105];
+ // [105] -> [111] : hit test x, y, z, rx, ry, rz, rw
+ private static readonly float[] _dataArray = new float[112];
// Shared float array with javascript.
// [0] : number of views (0 : session is stopped)
@@ -429,7 +472,9 @@ public static string Stringify()
// [45] : Right controller active
// [46] : Left hand active
// [47] : Right hand active
- private static readonly byte[] _byteArray = new byte[48];
+ // [48] : Hit test in progress
+ // [49] : Hit test supported
+ private static readonly byte[] _byteArray = new byte[50];
// Hand data
// [0] -> [7] : Left Wrist x, y, z, rx, ry, rz, zw, radius
@@ -664,6 +709,17 @@ private static void RaiseInputSourceEvent(byte mask, WebXRInputSourceEventTypes
}
}
+
+ // Update the hit test infos
+ private static void UpdateHitTest()
+ {
+ if (HitTestInProgress)
+ {
+ HitTestPosition = ToUnityPosition(_dataArray[105], _dataArray[106], _dataArray[107]);
+ HitTestRotation = ToUnityRotation(_dataArray[108], _dataArray[109], _dataArray[110], _dataArray[111]);
+ }
+ }
+
// Converts a WebGL position coordinate to a Unity position coordinate
private static Vector3 ToUnityPosition(float x, float y, float z)
{
@@ -700,6 +756,13 @@ private static Quaternion ToUnityRotation(float x, float y, float z, float w)
[DllImport("__Internal")]
private static extern bool InternalIsVrSupported();
+ [DllImport("__Internal")]
+ private static extern void InternalHitTestStart();
+
+ [DllImport("__Internal")]
+ private static extern void InternalHitTestCancel();
+
+
[DllImport("__Internal")]
private static extern void InternalGetDeviceOrientation(float[] orientationArray, byte[] orientationInfo);
@@ -715,10 +778,14 @@ private static void InitWebXR(float[] dataArray, int length, byte[] _byteArray,
private static bool InternalIsVrSupported() => false;
private static void InternalGetDeviceOrientation(float[] orientationArray, byte[] orientationInfo) { }
+
+ private static void InternalHitTestStart() { }
+
+ private static void InternalHitTestCancel() { }
#endif
- [System.Flags]
+ [System.Flags]
private enum WebXRViewEyes
{
None = 0,