David Mohrhardt
6 年前
当前提交
8fda7bf0
共有 15 个文件被更改,包括 506 次插入 和 214 次删除
-
2Assets/Prefabs/AR Eye Pose Visualizer.prefab
-
77Assets/Materials/EyeLaserMaterial.mat
-
8Assets/Materials/EyeLaserMaterial.mat.meta
-
227Assets/Prefabs/EyeLaserPrefab.prefab
-
7Assets/Prefabs/EyeLaserPrefab.prefab.meta
-
97Assets/Scripts/EyePoseVisualizer.cs
-
89Assets/Scripts/FixationPointVisualizer.cs
-
111Assets/Scripts/ARKitEyePoseVisualizer.cs
-
102Assets/Scripts/ARKitFixationPointVisualizer.cs
-
0/Assets/Scenes/FaceTracking/FixationPoint.unity
-
0/Assets/Scenes/FaceTracking/FixationPoint.unity.meta
-
0/Assets/Scenes/FaceTracking/EyePoses.unity
-
0/Assets/Scenes/FaceTracking/EyePoses.unity.meta
-
0/Assets/Scripts/EyePoseVisualizer.cs.meta
-
0/Assets/Scripts/FixationPointVisualizer.cs.meta
|
|||
%YAML 1.1 |
|||
%TAG !u! tag:unity3d.com,2011: |
|||
--- !u!21 &2100000 |
|||
Material: |
|||
serializedVersion: 6 |
|||
m_ObjectHideFlags: 0 |
|||
m_CorrespondingSourceObject: {fileID: 0} |
|||
m_PrefabInstance: {fileID: 0} |
|||
m_PrefabAsset: {fileID: 0} |
|||
m_Name: New Material |
|||
m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} |
|||
m_ShaderKeywords: |
|||
m_LightmapFlags: 4 |
|||
m_EnableInstancingVariants: 0 |
|||
m_DoubleSidedGI: 0 |
|||
m_CustomRenderQueue: -1 |
|||
stringTagMap: {} |
|||
disabledShaderPasses: [] |
|||
m_SavedProperties: |
|||
serializedVersion: 3 |
|||
m_TexEnvs: |
|||
- _BumpMap: |
|||
m_Texture: {fileID: 0} |
|||
m_Scale: {x: 1, y: 1} |
|||
m_Offset: {x: 0, y: 0} |
|||
- _DetailAlbedoMap: |
|||
m_Texture: {fileID: 0} |
|||
m_Scale: {x: 1, y: 1} |
|||
m_Offset: {x: 0, y: 0} |
|||
- _DetailMask: |
|||
m_Texture: {fileID: 0} |
|||
m_Scale: {x: 1, y: 1} |
|||
m_Offset: {x: 0, y: 0} |
|||
- _DetailNormalMap: |
|||
m_Texture: {fileID: 0} |
|||
m_Scale: {x: 1, y: 1} |
|||
m_Offset: {x: 0, y: 0} |
|||
- _EmissionMap: |
|||
m_Texture: {fileID: 0} |
|||
m_Scale: {x: 1, y: 1} |
|||
m_Offset: {x: 0, y: 0} |
|||
- _MainTex: |
|||
m_Texture: {fileID: 0} |
|||
m_Scale: {x: 1, y: 1} |
|||
m_Offset: {x: 0, y: 0} |
|||
- _MetallicGlossMap: |
|||
m_Texture: {fileID: 0} |
|||
m_Scale: {x: 1, y: 1} |
|||
m_Offset: {x: 0, y: 0} |
|||
- _OcclusionMap: |
|||
m_Texture: {fileID: 0} |
|||
m_Scale: {x: 1, y: 1} |
|||
m_Offset: {x: 0, y: 0} |
|||
- _ParallaxMap: |
|||
m_Texture: {fileID: 0} |
|||
m_Scale: {x: 1, y: 1} |
|||
m_Offset: {x: 0, y: 0} |
|||
m_Floats: |
|||
- _BumpScale: 1 |
|||
- _Cutoff: 0.5 |
|||
- _DetailNormalMapScale: 1 |
|||
- _DstBlend: 0 |
|||
- _GlossMapScale: 1 |
|||
- _Glossiness: 0.5 |
|||
- _GlossyReflections: 1 |
|||
- _Metallic: 0 |
|||
- _Mode: 0 |
|||
- _OcclusionStrength: 1 |
|||
- _Parallax: 0.02 |
|||
- _SmoothnessTextureChannel: 0 |
|||
- _SpecularHighlights: 1 |
|||
- _SrcBlend: 1 |
|||
- _UVSec: 0 |
|||
- _ZWrite: 1 |
|||
m_Colors: |
|||
- _Color: {r: 1, g: 1, b: 1, a: 1} |
|||
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1} |
|
|||
fileFormatVersion: 2 |
|||
guid: b0a46feb4b70f43f88f599f902d3a3a6 |
|||
NativeFormatImporter: |
|||
externalObjects: {} |
|||
mainObjectFileID: 2100000 |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
%YAML 1.1 |
|||
%TAG !u! tag:unity3d.com,2011: |
|||
--- !u!1 &6955206987099554130 |
|||
GameObject: |
|||
m_ObjectHideFlags: 0 |
|||
m_CorrespondingSourceObject: {fileID: 8219826597749932234, guid: 73d46f3fb3c4d4f6d8e1b7f94cd0086d, |
|||
type: 3} |
|||
m_PrefabInstance: {fileID: 0} |
|||
m_PrefabAsset: {fileID: 0} |
|||
serializedVersion: 6 |
|||
m_Component: |
|||
- component: {fileID: 6955206987099554141} |
|||
m_Layer: 0 |
|||
m_Name: EyeLaserPrefab |
|||
m_TagString: Untagged |
|||
m_Icon: {fileID: 0} |
|||
m_NavMeshLayer: 0 |
|||
m_StaticEditorFlags: 0 |
|||
m_IsActive: 1 |
|||
--- !u!4 &6955206987099554141 |
|||
Transform: |
|||
m_ObjectHideFlags: 0 |
|||
m_CorrespondingSourceObject: {fileID: 8219826597749932229, guid: 73d46f3fb3c4d4f6d8e1b7f94cd0086d, |
|||
type: 3} |
|||
m_PrefabInstance: {fileID: 0} |
|||
m_PrefabAsset: {fileID: 0} |
|||
m_GameObject: {fileID: 6955206987099554130} |
|||
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: |
|||
- {fileID: 6955206988088962637} |
|||
- {fileID: 1812003408609695089} |
|||
m_Father: {fileID: 0} |
|||
m_RootOrder: 0 |
|||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} |
|||
--- !u!1 &6955206988088962626 |
|||
GameObject: |
|||
m_ObjectHideFlags: 0 |
|||
m_CorrespondingSourceObject: {fileID: 8219826596757401562, guid: 73d46f3fb3c4d4f6d8e1b7f94cd0086d, |
|||
type: 3} |
|||
m_PrefabInstance: {fileID: 0} |
|||
m_PrefabAsset: {fileID: 0} |
|||
serializedVersion: 6 |
|||
m_Component: |
|||
- component: {fileID: 6955206988088962637} |
|||
- component: {fileID: 6955206988088962638} |
|||
- component: {fileID: 6955206988088962639} |
|||
- component: {fileID: 6955206988088962636} |
|||
m_Layer: 0 |
|||
m_Name: Cylinder |
|||
m_TagString: Untagged |
|||
m_Icon: {fileID: 0} |
|||
m_NavMeshLayer: 0 |
|||
m_StaticEditorFlags: 0 |
|||
m_IsActive: 1 |
|||
--- !u!4 &6955206988088962637 |
|||
Transform: |
|||
m_ObjectHideFlags: 0 |
|||
m_CorrespondingSourceObject: {fileID: 8219826596757401557, guid: 73d46f3fb3c4d4f6d8e1b7f94cd0086d, |
|||
type: 3} |
|||
m_PrefabInstance: {fileID: 0} |
|||
m_PrefabAsset: {fileID: 0} |
|||
m_GameObject: {fileID: 6955206988088962626} |
|||
m_LocalRotation: {x: 0.7071068, y: -0, z: -0, w: 0.7071068} |
|||
m_LocalPosition: {x: 0, y: 0, z: -100} |
|||
m_LocalScale: {x: 0.01, y: 100.00018, z: 0.0100000035} |
|||
m_Children: [] |
|||
m_Father: {fileID: 6955206987099554141} |
|||
m_RootOrder: 0 |
|||
m_LocalEulerAnglesHint: {x: 90, y: 0, z: 0} |
|||
--- !u!33 &6955206988088962638 |
|||
MeshFilter: |
|||
m_ObjectHideFlags: 0 |
|||
m_CorrespondingSourceObject: {fileID: 8219826596757401558, guid: 73d46f3fb3c4d4f6d8e1b7f94cd0086d, |
|||
type: 3} |
|||
m_PrefabInstance: {fileID: 0} |
|||
m_PrefabAsset: {fileID: 0} |
|||
m_GameObject: {fileID: 6955206988088962626} |
|||
m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0} |
|||
--- !u!23 &6955206988088962639 |
|||
MeshRenderer: |
|||
m_ObjectHideFlags: 0 |
|||
m_CorrespondingSourceObject: {fileID: 8219826596757401559, guid: 73d46f3fb3c4d4f6d8e1b7f94cd0086d, |
|||
type: 3} |
|||
m_PrefabInstance: {fileID: 0} |
|||
m_PrefabAsset: {fileID: 0} |
|||
m_GameObject: {fileID: 6955206988088962626} |
|||
m_Enabled: 1 |
|||
m_CastShadows: 1 |
|||
m_ReceiveShadows: 1 |
|||
m_DynamicOccludee: 1 |
|||
m_MotionVectors: 1 |
|||
m_LightProbeUsage: 1 |
|||
m_ReflectionProbeUsage: 1 |
|||
m_RenderingLayerMask: 1 |
|||
m_RendererPriority: 0 |
|||
m_Materials: |
|||
- {fileID: 2100000, guid: d80c1a202911a4a37a3da59992876dfc, type: 2} |
|||
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!136 &6955206988088962636 |
|||
CapsuleCollider: |
|||
m_ObjectHideFlags: 0 |
|||
m_CorrespondingSourceObject: {fileID: 8219826596757401556, guid: 73d46f3fb3c4d4f6d8e1b7f94cd0086d, |
|||
type: 3} |
|||
m_PrefabInstance: {fileID: 0} |
|||
m_PrefabAsset: {fileID: 0} |
|||
m_GameObject: {fileID: 6955206988088962626} |
|||
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!1 &7515971284296877401 |
|||
GameObject: |
|||
m_ObjectHideFlags: 0 |
|||
m_CorrespondingSourceObject: {fileID: 0} |
|||
m_PrefabInstance: {fileID: 0} |
|||
m_PrefabAsset: {fileID: 0} |
|||
serializedVersion: 6 |
|||
m_Component: |
|||
- component: {fileID: 1812003408609695089} |
|||
- component: {fileID: 8461321011708531416} |
|||
- component: {fileID: 7261203333575764417} |
|||
- component: {fileID: 5432332615467607901} |
|||
m_Layer: 0 |
|||
m_Name: Interior Cylinder |
|||
m_TagString: Untagged |
|||
m_Icon: {fileID: 0} |
|||
m_NavMeshLayer: 0 |
|||
m_StaticEditorFlags: 0 |
|||
m_IsActive: 1 |
|||
--- !u!4 &1812003408609695089 |
|||
Transform: |
|||
m_ObjectHideFlags: 0 |
|||
m_CorrespondingSourceObject: {fileID: 0} |
|||
m_PrefabInstance: {fileID: 0} |
|||
m_PrefabAsset: {fileID: 0} |
|||
m_GameObject: {fileID: 7515971284296877401} |
|||
m_LocalRotation: {x: 0.7071068, y: -0, z: -0, w: 0.7071068} |
|||
m_LocalPosition: {x: 0, y: 0, z: -100} |
|||
m_LocalScale: {x: -0.01, y: -100.0003, z: -0.01} |
|||
m_Children: [] |
|||
m_Father: {fileID: 6955206987099554141} |
|||
m_RootOrder: 1 |
|||
m_LocalEulerAnglesHint: {x: 90, y: 0, z: 0} |
|||
--- !u!33 &8461321011708531416 |
|||
MeshFilter: |
|||
m_ObjectHideFlags: 0 |
|||
m_CorrespondingSourceObject: {fileID: 0} |
|||
m_PrefabInstance: {fileID: 0} |
|||
m_PrefabAsset: {fileID: 0} |
|||
m_GameObject: {fileID: 7515971284296877401} |
|||
m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0} |
|||
--- !u!23 &7261203333575764417 |
|||
MeshRenderer: |
|||
m_ObjectHideFlags: 0 |
|||
m_CorrespondingSourceObject: {fileID: 0} |
|||
m_PrefabInstance: {fileID: 0} |
|||
m_PrefabAsset: {fileID: 0} |
|||
m_GameObject: {fileID: 7515971284296877401} |
|||
m_Enabled: 1 |
|||
m_CastShadows: 1 |
|||
m_ReceiveShadows: 1 |
|||
m_DynamicOccludee: 1 |
|||
m_MotionVectors: 1 |
|||
m_LightProbeUsage: 1 |
|||
m_ReflectionProbeUsage: 1 |
|||
m_RenderingLayerMask: 1 |
|||
m_RendererPriority: 0 |
|||
m_Materials: |
|||
- {fileID: 2100000, guid: d80c1a202911a4a37a3da59992876dfc, type: 2} |
|||
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!136 &5432332615467607901 |
|||
CapsuleCollider: |
|||
m_ObjectHideFlags: 0 |
|||
m_CorrespondingSourceObject: {fileID: 0} |
|||
m_PrefabInstance: {fileID: 0} |
|||
m_PrefabAsset: {fileID: 0} |
|||
m_GameObject: {fileID: 7515971284296877401} |
|||
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} |
|
|||
fileFormatVersion: 2 |
|||
guid: 73d46f3fb3c4d4f6d8e1b7f94cd0086d |
|||
PrefabImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using UnityEngine; |
|||
using UnityEngine.XR.ARFoundation; |
|||
using UnityEngine.XR.ARSubsystems; |
|||
#if UNITY_IOS && !UNITY_EDITOR
|
|||
using UnityEngine.XR.ARKit; |
|||
#endif
|
|||
|
|||
/// <summary>
|
|||
/// Visualizes the eye poses for an <see cref="ARFace"/>.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// Face space is the space where the origin is the transform of an <see cref="ARFace"/>.
|
|||
/// </remarks>
|
|||
[RequireComponent(typeof(ARFace))] |
|||
public class EyePoseVisualizer : MonoBehaviour |
|||
{ |
|||
[SerializeField] |
|||
GameObject m_EyePrefab; |
|||
|
|||
public GameObject eyePrefab |
|||
{ |
|||
get => m_EyePrefab; |
|||
set => m_EyePrefab = value; |
|||
} |
|||
|
|||
GameObject m_LeftEyeGameObject; |
|||
GameObject m_RightEyeGameObject; |
|||
|
|||
ARFace m_Face; |
|||
XRFaceSubsystem m_FaceSubsystem; |
|||
|
|||
void Awake() |
|||
{ |
|||
m_Face = GetComponent<ARFace>(); |
|||
CreateEyeGameObjects(); |
|||
} |
|||
|
|||
void CreateEyeGameObjects() |
|||
{ |
|||
m_LeftEyeGameObject = Instantiate(m_EyePrefab, m_Face.transform); |
|||
m_RightEyeGameObject = Instantiate(m_EyePrefab, m_Face.transform); |
|||
|
|||
m_LeftEyeGameObject.SetActive(false); |
|||
m_RightEyeGameObject.SetActive(false); |
|||
} |
|||
|
|||
void SetVisible(bool visible) |
|||
{ |
|||
m_LeftEyeGameObject.SetActive(visible); |
|||
m_RightEyeGameObject.SetActive(visible); |
|||
} |
|||
|
|||
void UpdateVisibility() |
|||
{ |
|||
var visible = |
|||
enabled && |
|||
(m_Face.trackingState == TrackingState.Tracking) && |
|||
m_FaceSubsystem.SubsystemDescriptor.supportsEyeTracking && |
|||
(ARSession.state > ARSessionState.Ready); |
|||
|
|||
SetVisible(visible); |
|||
} |
|||
|
|||
void OnEnable() |
|||
{ |
|||
var faceManager = FindObjectOfType<ARFaceManager>(); |
|||
if (faceManager != null) |
|||
{ |
|||
m_FaceSubsystem = (XRFaceSubsystem)faceManager.subsystem; |
|||
} |
|||
UpdateVisibility(); |
|||
m_Face.updated += OnUpdated; |
|||
} |
|||
|
|||
void OnUpdated(ARFaceUpdatedEventArgs eventArgs) |
|||
{ |
|||
UpdateVisibility(); |
|||
UpdateEyeGazeFeatures(); |
|||
} |
|||
|
|||
void UpdateEyeGazeFeatures() |
|||
{ |
|||
if (m_FaceSubsystem.SubsystemDescriptor.supportsEyeTracking) |
|||
{ |
|||
m_LeftEyeGameObject.transform.localPosition = m_Face.leftEyePose.Value.position; |
|||
m_LeftEyeGameObject.transform.localRotation = m_Face.leftEyePose.Value.rotation; |
|||
m_RightEyeGameObject.transform.localPosition = m_Face.rightEyePose.Value.position; |
|||
m_RightEyeGameObject.transform.localRotation = m_Face.rightEyePose.Value.rotation; |
|||
} |
|||
else |
|||
{ |
|||
Debug.Log("This subsystem does not support eye tracking."); |
|||
} |
|||
} |
|||
} |
|
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using UnityEngine; |
|||
using UnityEngine.XR.ARFoundation; |
|||
using UnityEngine.XR.ARSubsystems; |
|||
|
|||
/// <summary>
|
|||
/// Visualizes the eye gaze position in face space for an <see cref="ARFace"/>.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// Face space is the space where the origin is the transform of an <see cref="ARFace"/>.
|
|||
/// </remarks>
|
|||
[RequireComponent(typeof(ARFace))] |
|||
public class FixationPointVisualizer : MonoBehaviour |
|||
{ |
|||
[SerializeField] |
|||
GameObject m_FixationPointPrefab; |
|||
|
|||
public GameObject fixationPointPrefab |
|||
{ |
|||
get => m_FixationPointPrefab; |
|||
set => m_FixationPointPrefab = value; |
|||
} |
|||
|
|||
GameObject m_FixationPointGameObject; |
|||
|
|||
ARFace m_Face; |
|||
XRFaceSubsystem m_FaceSubsystem; |
|||
|
|||
void Awake() |
|||
{ |
|||
m_Face = GetComponent<ARFace>(); |
|||
CreateEyeGameObjects(); |
|||
} |
|||
|
|||
void CreateEyeGameObjects() |
|||
{ |
|||
m_FixationPointGameObject = Instantiate(m_FixationPointPrefab, m_Face.transform); |
|||
m_FixationPointGameObject.SetActive(false); |
|||
} |
|||
|
|||
void SetVisible(bool visible) |
|||
{ |
|||
m_FixationPointGameObject.SetActive(visible); |
|||
} |
|||
|
|||
void UpdateVisibility() |
|||
{ |
|||
var visible = |
|||
enabled && |
|||
(m_Face.trackingState == TrackingState.Tracking) && |
|||
m_FaceSubsystem.SubsystemDescriptor.supportsEyeTracking && |
|||
(ARSession.state > ARSessionState.Ready); |
|||
|
|||
SetVisible(visible); |
|||
} |
|||
|
|||
void OnEnable() |
|||
{ |
|||
var faceManager = FindObjectOfType<ARFaceManager>(); |
|||
if (faceManager != null) |
|||
{ |
|||
m_FaceSubsystem = (XRFaceSubsystem)faceManager.subsystem; |
|||
} |
|||
UpdateVisibility(); |
|||
m_Face.updated += OnUpdated; |
|||
} |
|||
|
|||
void OnUpdated(ARFaceUpdatedEventArgs eventArgs) |
|||
{ |
|||
UpdateVisibility(); |
|||
UpdateFixationPoint(); |
|||
} |
|||
|
|||
void UpdateFixationPoint() |
|||
{ |
|||
if (m_Face.fixationPoint != null) |
|||
{ |
|||
// Often the gaze point will be the device (origin) or past the device so for demonstration
|
|||
// sake, we scale back the position to be closer (approx. 10cm) to the face and therefore visible.
|
|||
m_FixationPointGameObject.transform.localPosition = Vector3.Normalize(m_Face.fixationPoint.Value) / 10; |
|||
} |
|||
else |
|||
{ |
|||
// Update onscreen text to show that eye tracking isn't supported
|
|||
} |
|||
} |
|||
|
|||
} |
|
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using UnityEngine; |
|||
using UnityEngine.XR.ARFoundation; |
|||
using UnityEngine.XR.ARSubsystems; |
|||
#if UNITY_IOS && !UNITY_EDITOR
|
|||
using UnityEngine.XR.ARKit; |
|||
#endif
|
|||
|
|||
/// <summary>
|
|||
/// Visualizes the eye poses for an <see cref="ARFace"/>.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// Face space is the space where the origin is the transform of an <see cref="ARFace"/>.
|
|||
/// </remarks>
|
|||
[RequireComponent(typeof(ARFace))] |
|||
public class ARKitEyePoseVisualizer : MonoBehaviour |
|||
{ |
|||
[SerializeField] |
|||
GameObject m_EyePrefab; |
|||
|
|||
public GameObject eyePrefab |
|||
{ |
|||
get => m_EyePrefab; |
|||
set => m_EyePrefab = value; |
|||
} |
|||
|
|||
GameObject m_LeftEyeGameObject; |
|||
GameObject m_RightEyeGameObject; |
|||
|
|||
ARFace m_Face; |
|||
#if UNITY_IOS && !UNITY_EDITOR
|
|||
XRFaceSubsystem m_FaceSubsystem; |
|||
#endif
|
|||
|
|||
void Awake() |
|||
{ |
|||
m_Face = GetComponent<ARFace>(); |
|||
CreateEyeGameObjects(); |
|||
} |
|||
|
|||
void CreateEyeGameObjects() |
|||
{ |
|||
m_LeftEyeGameObject = Instantiate(m_EyePrefab, m_Face.transform); |
|||
m_RightEyeGameObject = Instantiate(m_EyePrefab, m_Face.transform); |
|||
|
|||
m_LeftEyeGameObject.SetActive(false); |
|||
m_RightEyeGameObject.SetActive(false); |
|||
} |
|||
|
|||
void SetVisible(bool visible) |
|||
{ |
|||
m_LeftEyeGameObject.SetActive(visible); |
|||
m_RightEyeGameObject.SetActive(visible); |
|||
} |
|||
|
|||
void UpdateVisibility() |
|||
{ |
|||
var visible = |
|||
enabled && |
|||
(m_Face.trackingState == TrackingState.Tracking) && |
|||
#if UNITY_IOS && !UNITY_EDITOR
|
|||
m_FaceSubsystem.supportedEyeTracking && |
|||
#endif
|
|||
(ARSession.state > ARSessionState.Ready); |
|||
|
|||
SetVisible(visible); |
|||
} |
|||
|
|||
void OnEnable() |
|||
{ |
|||
#if UNITY_IOS && !UNITY_EDITOR
|
|||
var faceManager = FindObjectOfType<ARFaceManager>(); |
|||
if (faceManager != null) |
|||
{ |
|||
m_FaceSubsystem = (XRFaceSubsystem)faceManager.subsystem; |
|||
} |
|||
#endif
|
|||
UpdateVisibility(); |
|||
m_Face.updated += OnUpdated; |
|||
} |
|||
|
|||
void OnUpdated(ARFaceUpdatedEventArgs eventArgs) |
|||
{ |
|||
UpdateVisibility(); |
|||
UpdateEyeGazeFeatures(); |
|||
} |
|||
|
|||
void UpdateEyeGazeFeatures() |
|||
{ |
|||
#if UNITY_IOS && !UNITY_EDITOR
|
|||
var leftEyePose = new Pose(); |
|||
var rightEyePose = new Pose(); |
|||
|
|||
if (m_FaceSubsystem.supportedEyeTracking) |
|||
{ |
|||
if (m_FaceSubsystem.TryGetLeftEyePose(m_Face.trackableId, ref leftEyePose) && m_FaceSubsystem.TryGetRightEyePose(m_Face.trackableId, ref rightEyePose)) |
|||
{ |
|||
m_LeftEyeGameObject.transform.localPosition = leftEyePose.position; |
|||
m_LeftEyeGameObject.transform.localRotation = leftEyePose.rotation; |
|||
m_RightEyeGameObject.transform.localPosition = rightEyePose.position; |
|||
m_RightEyeGameObject.transform.localRotation = rightEyePose.rotation; |
|||
} |
|||
else |
|||
{ |
|||
Debug.Log("Failed to get the face's eye poses."); |
|||
} |
|||
} |
|||
#endif
|
|||
} |
|||
} |
|
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using UnityEngine; |
|||
using UnityEngine.XR.ARFoundation; |
|||
using UnityEngine.XR.ARSubsystems; |
|||
|
|||
/// <summary>
|
|||
/// Visualizes the eye gaze position in face space for an <see cref="ARFace"/>.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// Face space is the space where the origin is the transform of an <see cref="ARFace"/>.
|
|||
/// </remarks>
|
|||
[RequireComponent(typeof(ARFace))] |
|||
public class ARKitFixationPointVisualizer : MonoBehaviour |
|||
{ |
|||
[SerializeField] |
|||
GameObject m_FixationPointPrefab; |
|||
|
|||
public GameObject fixationPointPrefab |
|||
{ |
|||
get => m_FixationPointPrefab; |
|||
set => m_FixationPointPrefab = value; |
|||
} |
|||
|
|||
GameObject m_FixationPointGameObject; |
|||
|
|||
ARFace m_Face; |
|||
#if UNITY_IOS && !UNITY_EDITOR
|
|||
XRFaceSubsystem m_FaceSubsystem; |
|||
#endif
|
|||
|
|||
void Awake() |
|||
{ |
|||
m_Face = GetComponent<ARFace>(); |
|||
CreateEyeGameObjects(); |
|||
} |
|||
|
|||
void CreateEyeGameObjects() |
|||
{ |
|||
m_FixationPointGameObject = Instantiate(m_FixationPointPrefab, m_Face.transform); |
|||
m_FixationPointGameObject.SetActive(false); |
|||
} |
|||
|
|||
void SetVisible(bool visible) |
|||
{ |
|||
m_FixationPointGameObject.SetActive(visible); |
|||
} |
|||
|
|||
void UpdateVisibility() |
|||
{ |
|||
var visible = |
|||
enabled && |
|||
(m_Face.trackingState == TrackingState.Tracking) && |
|||
#if UNITY_IOS && !UNITY_EDITOR
|
|||
m_FaceSubsystem.supportedEyeTracking && |
|||
#endif
|
|||
(ARSession.state > ARSessionState.Ready); |
|||
|
|||
SetVisible(visible); |
|||
} |
|||
|
|||
void OnEnable() |
|||
{ |
|||
#if UNITY_IOS && !UNITY_EDITOR
|
|||
var faceManager = FindObjectOfType<ARFaceManager>(); |
|||
if (faceManager != null) |
|||
{ |
|||
m_FaceSubsystem = (XRFaceSubsystem)faceManager.subsystem; |
|||
} |
|||
#endif
|
|||
UpdateVisibility(); |
|||
m_Face.updated += OnUpdated; |
|||
} |
|||
|
|||
void OnUpdated(ARFaceUpdatedEventArgs eventArgs) |
|||
{ |
|||
UpdateVisibility(); |
|||
UpdateFixationPoint(); |
|||
} |
|||
|
|||
void UpdateFixationPoint() |
|||
{ |
|||
#if UNITY_IOS && !UNITY_EDITOR
|
|||
var fixationPoint = new Vector3(); |
|||
|
|||
if (m_FaceSubsystem.supportedEyeTracking) |
|||
{ |
|||
if (m_FaceSubsystem.TryGetFixationPoint(m_Face.trackableId, ref fixationPoint)) |
|||
{ |
|||
// The vector that represents the gaze offset from the face is not normalized and therefore could be behind the camera.
|
|||
// So set the offset to be 1/10th of meter in the direction of the offset
|
|||
m_FixationPointGameObject.transform.localPosition = Vector3.Normalize(fixationPoint) / 10; |
|||
} |
|||
else |
|||
{ |
|||
Debug.Log("Failed to get the face's fixation point."); |
|||
} |
|||
} |
|||
#endif
|
|||
} |
|||
|
|||
} |
撰写
预览
正在加载...
取消
保存
Reference in new issue