diff --git a/Prefabs/Pointers.meta b/Prefabs/Pointers.meta new file mode 100644 index 00000000..5729c18f --- /dev/null +++ b/Prefabs/Pointers.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e16b50fc4d479c3479d4bd866fc004ec +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Prefabs/Pointers/SharedResources.meta b/Prefabs/Pointers/SharedResources.meta new file mode 100644 index 00000000..a4bd6772 --- /dev/null +++ b/Prefabs/Pointers/SharedResources.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 19ae4898bfbf1d54aad099b8387a0556 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Prefabs/Pointers/SharedResources/Materials.meta b/Prefabs/Pointers/SharedResources/Materials.meta new file mode 100644 index 00000000..a47a6314 --- /dev/null +++ b/Prefabs/Pointers/SharedResources/Materials.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b2277dc64d10b534b9bc36f9b3d2c609 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Prefabs/Pointers/SharedResources/Materials/PointerDefaultInvalid.mat b/Prefabs/Pointers/SharedResources/Materials/PointerDefaultInvalid.mat new file mode 100644 index 00000000..872bf6c6 --- /dev/null +++ b/Prefabs/Pointers/SharedResources/Materials/PointerDefaultInvalid.mat @@ -0,0 +1,76 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_Name: PointerDefaultInvalid + m_Shader: {fileID: 4800000, guid: c6488aa155d56e042b5ff808b89c7dda, type: 3} + 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: 0, b: 0, a: 0.5882353} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/Prefabs/Pointers/SharedResources/Materials/PointerDefaultInvalid.mat.meta b/Prefabs/Pointers/SharedResources/Materials/PointerDefaultInvalid.mat.meta new file mode 100644 index 00000000..b4794be0 --- /dev/null +++ b/Prefabs/Pointers/SharedResources/Materials/PointerDefaultInvalid.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3ea92609994834245baf997807c5677c +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Prefabs/Pointers/SharedResources/Materials/PointerDefaultValid.mat b/Prefabs/Pointers/SharedResources/Materials/PointerDefaultValid.mat new file mode 100644 index 00000000..577bb9fd --- /dev/null +++ b/Prefabs/Pointers/SharedResources/Materials/PointerDefaultValid.mat @@ -0,0 +1,76 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_Name: PointerDefaultValid + m_Shader: {fileID: 4800000, guid: c6488aa155d56e042b5ff808b89c7dda, type: 3} + 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: 0, g: 1, b: 0, a: 0.5882353} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/Prefabs/Pointers/SharedResources/Materials/PointerDefaultValid.mat.meta b/Prefabs/Pointers/SharedResources/Materials/PointerDefaultValid.mat.meta new file mode 100644 index 00000000..ddbad4c8 --- /dev/null +++ b/Prefabs/Pointers/SharedResources/Materials/PointerDefaultValid.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 45363d50487514f40be10a6626b8874d +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Prefabs/Pointers/SolidParabolicPointer.prefab b/Prefabs/Pointers/SolidParabolicPointer.prefab new file mode 100644 index 00000000..fc70ea72 --- /dev/null +++ b/Prefabs/Pointers/SolidParabolicPointer.prefab @@ -0,0 +1,732 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1001 &100100000 +Prefab: + m_ObjectHideFlags: 1 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: [] + m_RemovedComponents: [] + m_ParentPrefab: {fileID: 0} + m_RootGameObject: {fileID: 1897668919043294} + m_IsPrefabParent: 1 +--- !u!1 &1070217285575164 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 4990198347560228} + m_Layer: 0 + m_Name: Middle + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1116056273701772 +GameObject: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 4573320480551876} + - component: {fileID: 33364052698962962} + - component: {fileID: 23996761392651784} + m_Layer: 0 + m_Name: InvalidTracer + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1200714994868418 +GameObject: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 4755503614305096} + - component: {fileID: 33677716766495152} + - component: {fileID: 23339715944455470} + m_Layer: 0 + m_Name: InvalidCursor + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1224850404600106 +GameObject: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 4417887466734172} + - component: {fileID: 33038519180947900} + - component: {fileID: 23829347887679280} + m_Layer: 0 + m_Name: ActualObject + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1309279854652330 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 4273869243677338} + m_Layer: 0 + m_Name: Cursor + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1459395790049962 +GameObject: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 4516217194393388} + - component: {fileID: 33603319313222156} + - component: {fileID: 23403056193514100} + m_Layer: 0 + m_Name: ValidTracer + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1529330592552216 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 4051388704589450} + m_Layer: 0 + m_Name: Tracer + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1547702833113128 +GameObject: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 4301982990135466} + - component: {fileID: 33635014065063646} + - component: {fileID: 23655827314840474} + m_Layer: 0 + m_Name: ActualObject + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1571008921183954 +GameObject: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 4331298706467906} + m_Layer: 0 + m_Name: ValidMiddle + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1846780609845688 +GameObject: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 4936146464785312} + m_Layer: 0 + m_Name: InvalidMiddle + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1897668919043294 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 4748404725061138} + - component: {fileID: 114967402694328888} + - component: {fileID: 114921987913562258} + - component: {fileID: 114802851438685276} + - component: {fileID: 114757610285119408} + - component: {fileID: 114043219088351336} + m_Layer: 0 + m_Name: SolidParabolicPointer + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1923595575554056 +GameObject: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 4767204780692922} + - component: {fileID: 33718780184033244} + - component: {fileID: 23433715969401368} + m_Layer: 0 + m_Name: ValidCursor + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &4051388704589450 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1529330592552216} + 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: 4516217194393388} + - {fileID: 4573320480551876} + m_Father: {fileID: 4748404725061138} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &4273869243677338 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1309279854652330} + 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: 4767204780692922} + - {fileID: 4755503614305096} + m_Father: {fileID: 4748404725061138} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &4301982990135466 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1547702833113128} + m_LocalRotation: {x: 0.7071068, y: 0, z: 0, w: 0.7071068} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.1, y: 1, z: 0.1} + m_Children: [] + m_Father: {fileID: 4331298706467906} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 90, y: 0, z: 0} +--- !u!4 &4331298706467906 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1571008921183954} + 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: 4301982990135466} + m_Father: {fileID: 4990198347560228} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &4417887466734172 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1224850404600106} + m_LocalRotation: {x: 0.7071068, y: -0, z: -0, w: 0.7071068} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.1, y: 1, z: 0.1} + m_Children: [] + m_Father: {fileID: 4936146464785312} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 90, y: 0, z: 0} +--- !u!4 &4516217194393388 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1459395790049962} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.05, y: 0.05, z: 0.05} + m_Children: [] + m_Father: {fileID: 4051388704589450} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &4573320480551876 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1116056273701772} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.05, y: 0.05, z: 0.05} + m_Children: [] + m_Father: {fileID: 4051388704589450} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &4748404725061138 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1897668919043294} + 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: 4051388704589450} + - {fileID: 4990198347560228} + - {fileID: 4273869243677338} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &4755503614305096 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1200714994868418} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.05, y: 0.05, z: 0.05} + m_Children: [] + m_Father: {fileID: 4273869243677338} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &4767204780692922 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1923595575554056} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.05, y: 0.05, z: 0.05} + m_Children: [] + m_Father: {fileID: 4273869243677338} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &4936146464785312 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1846780609845688} + 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: 4417887466734172} + m_Father: {fileID: 4990198347560228} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &4990198347560228 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1070217285575164} + 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: 4331298706467906} + - {fileID: 4936146464785312} + m_Father: {fileID: 4748404725061138} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!23 &23339715944455470 +MeshRenderer: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1200714994868418} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RenderingLayerMask: 4294967295 + m_Materials: + - {fileID: 2100000, guid: 3ea92609994834245baf997807c5677c, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + 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!23 &23403056193514100 +MeshRenderer: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1459395790049962} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RenderingLayerMask: 4294967295 + m_Materials: + - {fileID: 2100000, guid: 45363d50487514f40be10a6626b8874d, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + 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!23 &23433715969401368 +MeshRenderer: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1923595575554056} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RenderingLayerMask: 4294967295 + m_Materials: + - {fileID: 2100000, guid: 45363d50487514f40be10a6626b8874d, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + 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!23 &23655827314840474 +MeshRenderer: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1547702833113128} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RenderingLayerMask: 4294967295 + m_Materials: + - {fileID: 2100000, guid: 45363d50487514f40be10a6626b8874d, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + 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!23 &23829347887679280 +MeshRenderer: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1224850404600106} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RenderingLayerMask: 4294967295 + m_Materials: + - {fileID: 2100000, guid: 3ea92609994834245baf997807c5677c, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + 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!23 &23996761392651784 +MeshRenderer: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1116056273701772} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RenderingLayerMask: 4294967295 + m_Materials: + - {fileID: 2100000, guid: 3ea92609994834245baf997807c5677c, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + 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 &33038519180947900 +MeshFilter: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1224850404600106} + m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0} +--- !u!33 &33364052698962962 +MeshFilter: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1116056273701772} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!33 &33603319313222156 +MeshFilter: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1459395790049962} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!33 &33635014065063646 +MeshFilter: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1547702833113128} + m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0} +--- !u!33 &33677716766495152 +MeshFilter: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1200714994868418} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!33 &33718780184033244 +MeshFilter: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1923595575554056} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!114 &114043219088351336 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1897668919043294} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a11862926720f544fb5d904995c2b57b, type: 3} + m_Name: + m_EditorClassIdentifier: + process: + field: {fileID: 114967402694328888} + onlyProcessOnActiveAndEnabled: 1 +--- !u!114 &114757610285119408 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1897668919043294} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5c0eab237e25807459af1c5caf4d3d33, type: 3} + m_Name: + m_EditorClassIdentifier: + momentToProcess: 5 + processes: + - {fileID: 114043219088351336} +--- !u!114 &114802851438685276 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1897668919043294} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 255407672fbf4289a8950abfa476e0b0, type: 3} + m_Name: + m_EditorClassIdentifier: + pointsCast: {fileID: 114967402694328888} + scaleDirection: {x: 0, y: 0, z: 1} + tracer: + validObject: {fileID: 1459395790049962} + invalidObject: {fileID: 1116056273701772} + visibility: 0 + middle: + validObject: {fileID: 1571008921183954} + invalidObject: {fileID: 1846780609845688} + visibility: 0 + cursor: + validObject: {fileID: 1923595575554056} + invalidObject: {fileID: 1200714994868418} + visibility: 0 +--- !u!114 &114921987913562258 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1897668919043294} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5195ecf61608495884b10998b2c6d117, type: 3} + m_Name: + m_EditorClassIdentifier: + pointsCast: {fileID: 114967402694328888} + Entered: + m_PersistentCalls: + m_Calls: [] + m_TypeName: VRTK.Core.Pointer.Pointer+PointerUnityEvent, Assembly-CSharp, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + Exited: + m_PersistentCalls: + m_Calls: [] + m_TypeName: VRTK.Core.Pointer.Pointer+PointerUnityEvent, Assembly-CSharp, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + Hovering: + m_PersistentCalls: + m_Calls: [] + m_TypeName: VRTK.Core.Pointer.Pointer+PointerUnityEvent, Assembly-CSharp, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null +--- !u!114 &114967402694328888 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1897668919043294} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f57b1a00a82f48d3a19652931fc4887d, type: 3} + m_Name: + m_EditorClassIdentifier: + physicsCast: {fileID: 0} + targetValidity: {fileID: 0} + CastResultsChanged: + m_PersistentCalls: + m_Calls: [] + m_TypeName: VRTK.Core.Cast.PointsCast+PointsCastUnityEvent, Assembly-CSharp, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + maximumLength: {x: 10, y: Infinity} + heightLimitAngle: 100 + density: 10 + collisionCheckFrequency: 10 + curveOffset: 1 diff --git a/Prefabs/Pointers/SolidParabolicPointer.prefab.meta b/Prefabs/Pointers/SolidParabolicPointer.prefab.meta new file mode 100644 index 00000000..072cd187 --- /dev/null +++ b/Prefabs/Pointers/SolidParabolicPointer.prefab.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 85ab5ffc906134f4792a21f10e948a12 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 100100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Prefabs/Pointers/SolidStraightPointer.prefab b/Prefabs/Pointers/SolidStraightPointer.prefab new file mode 100644 index 00000000..c38cace4 --- /dev/null +++ b/Prefabs/Pointers/SolidStraightPointer.prefab @@ -0,0 +1,495 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1001 &100100000 +Prefab: + m_ObjectHideFlags: 1 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: [] + m_RemovedComponents: [] + m_ParentPrefab: {fileID: 0} + m_RootGameObject: {fileID: 1552269893497444} + m_IsPrefabParent: 1 +--- !u!1 &1151889711566436 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 4618714272313756} + m_Layer: 0 + m_Name: Tracer + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1195745717349208 +GameObject: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 4470840868069594} + - component: {fileID: 33842711365439030} + - component: {fileID: 23813864600538518} + m_Layer: 0 + m_Name: ValidCursor + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1268476617082826 +GameObject: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 4603804475465888} + - component: {fileID: 33314063943023140} + - component: {fileID: 23699266861947568} + m_Layer: 0 + m_Name: InvalidTracer + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1496519822845236 +GameObject: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 4579394868571944} + - component: {fileID: 33710724874815580} + - component: {fileID: 23383046084383780} + m_Layer: 0 + m_Name: InvalidCursor + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1552269893497444 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 4768196633265156} + - component: {fileID: 114710422162132952} + - component: {fileID: 114112185610041394} + - component: {fileID: 114990274115864700} + - component: {fileID: 114712552237190026} + - component: {fileID: 114365101931089768} + m_Layer: 0 + m_Name: SolidStraightPointer + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1558147321532568 +GameObject: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 4065798878235614} + - component: {fileID: 33408914329589152} + - component: {fileID: 23017688154559558} + m_Layer: 0 + m_Name: ValidTracer + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1833070260010384 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 4121294435962586} + m_Layer: 0 + m_Name: Cursor + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &4065798878235614 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1558147321532568} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.05, y: 0.05, z: 0.05} + m_Children: [] + m_Father: {fileID: 4618714272313756} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &4121294435962586 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1833070260010384} + 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: 4470840868069594} + - {fileID: 4579394868571944} + m_Father: {fileID: 4768196633265156} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &4470840868069594 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1195745717349208} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.05, y: 0.05, z: 0.05} + m_Children: [] + m_Father: {fileID: 4121294435962586} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &4579394868571944 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1496519822845236} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.05, y: 0.05, z: 0.05} + m_Children: [] + m_Father: {fileID: 4121294435962586} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &4603804475465888 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1268476617082826} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.005, y: 0.005, z: 0.005} + m_Children: [] + m_Father: {fileID: 4618714272313756} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &4618714272313756 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1151889711566436} + 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: 4065798878235614} + - {fileID: 4603804475465888} + m_Father: {fileID: 4768196633265156} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &4768196633265156 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1552269893497444} + 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: 4618714272313756} + - {fileID: 4121294435962586} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!23 &23017688154559558 +MeshRenderer: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1558147321532568} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RenderingLayerMask: 4294967295 + m_Materials: + - {fileID: 2100000, guid: 45363d50487514f40be10a6626b8874d, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + 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!23 &23383046084383780 +MeshRenderer: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1496519822845236} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RenderingLayerMask: 4294967295 + m_Materials: + - {fileID: 2100000, guid: 3ea92609994834245baf997807c5677c, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + 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!23 &23699266861947568 +MeshRenderer: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1268476617082826} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RenderingLayerMask: 4294967295 + m_Materials: + - {fileID: 2100000, guid: 3ea92609994834245baf997807c5677c, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + 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!23 &23813864600538518 +MeshRenderer: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1195745717349208} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RenderingLayerMask: 4294967295 + m_Materials: + - {fileID: 2100000, guid: 45363d50487514f40be10a6626b8874d, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + 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 &33314063943023140 +MeshFilter: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1268476617082826} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!33 &33408914329589152 +MeshFilter: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1558147321532568} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!33 &33710724874815580 +MeshFilter: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1496519822845236} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!33 &33842711365439030 +MeshFilter: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1195745717349208} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!114 &114112185610041394 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1552269893497444} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5195ecf61608495884b10998b2c6d117, type: 3} + m_Name: + m_EditorClassIdentifier: + pointsCast: {fileID: 114710422162132952} + Entered: + m_PersistentCalls: + m_Calls: [] + m_TypeName: VRTK.Core.Pointer.Pointer+PointerUnityEvent, Assembly-CSharp, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + Exited: + m_PersistentCalls: + m_Calls: [] + m_TypeName: VRTK.Core.Pointer.Pointer+PointerUnityEvent, Assembly-CSharp, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + Hovering: + m_PersistentCalls: + m_Calls: [] + m_TypeName: VRTK.Core.Pointer.Pointer+PointerUnityEvent, Assembly-CSharp, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null +--- !u!114 &114365101931089768 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1552269893497444} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a11862926720f544fb5d904995c2b57b, type: 3} + m_Name: + m_EditorClassIdentifier: + process: + field: {fileID: 114710422162132952} + onlyProcessOnActiveAndEnabled: 1 +--- !u!114 &114710422162132952 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1552269893497444} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 7934e9d7f2f8434c9358d4d4e8a14b6a, type: 3} + m_Name: + m_EditorClassIdentifier: + physicsCast: {fileID: 0} + targetValidity: {fileID: 0} + CastResultsChanged: + m_PersistentCalls: + m_Calls: [] + m_TypeName: VRTK.Core.Cast.PointsCast+PointsCastUnityEvent, Assembly-CSharp, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + maximumLength: 100 +--- !u!114 &114712552237190026 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1552269893497444} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5c0eab237e25807459af1c5caf4d3d33, type: 3} + m_Name: + m_EditorClassIdentifier: + momentToProcess: 5 + processes: + - {fileID: 114365101931089768} +--- !u!114 &114990274115864700 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1552269893497444} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 255407672fbf4289a8950abfa476e0b0, type: 3} + m_Name: + m_EditorClassIdentifier: + pointsCast: {fileID: 114710422162132952} + scaleDirection: {x: 0, y: 0, z: 1} + tracer: + validObject: {fileID: 1558147321532568} + invalidObject: {fileID: 1268476617082826} + visibility: 0 + middle: + validObject: {fileID: 1558147321532568} + invalidObject: {fileID: 1268476617082826} + visibility: 0 + cursor: + validObject: {fileID: 1195745717349208} + invalidObject: {fileID: 1496519822845236} + visibility: 0 diff --git a/Prefabs/Pointers/SolidStraightPointer.prefab.meta b/Prefabs/Pointers/SolidStraightPointer.prefab.meta new file mode 100644 index 00000000..f414335d --- /dev/null +++ b/Prefabs/Pointers/SolidStraightPointer.prefab.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 88f3454742388c943bc473e342a64467 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 100100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Cast.meta b/Scripts/Cast.meta new file mode 100644 index 00000000..12655a0e --- /dev/null +++ b/Scripts/Cast.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 156756a9266a4c42a4c9363aee845395 +timeCreated: 1526407015 \ No newline at end of file diff --git a/Scripts/Cast/ParabolicLineCast.cs b/Scripts/Cast/ParabolicLineCast.cs new file mode 100644 index 00000000..049f8438 --- /dev/null +++ b/Scripts/Cast/ParabolicLineCast.cs @@ -0,0 +1,178 @@ +namespace VRTK.Core.Cast +{ + using UnityEngine; + using VRTK.Core.Utility; + + /// + /// Casts a parabolic line and creates points at the origin, the target and in between. + /// + public class ParabolicLineCast : PointsCast + { + /// + /// Used to move the points back and up a bit to prevent the cast clipping at the collision points. + /// + protected const float ADJUSTMENT_OFFSET = 0.0001f; + + /// + /// The maximum length of the projected cast. The x value is the length of the forward cast, the y value is the length of the downward cast. + /// + [Tooltip("The maximum length of the projected cast. The x value is the length of the forward cast, the y value is the length of the downward cast.")] + public Vector2 maximumLength = new Vector2(10f, float.PositiveInfinity); + /// + /// The maximum angle in degrees of the origin before the cast line height is restricted. A lower angle setting will prevent the cast being projected high into the sky and curving back down. + /// + [Range(1, 100)] + [Tooltip("The maximum angle in degrees of the origin before the cast line height is restricted. A lower angle setting will prevent the cast being projected high into the sky and curving back down.")] + public float heightLimitAngle = 100f; + /// + /// The number of points to generate on the parabolic line. + /// + /// The higher the number, the more CPU intensive the point generation becomes. + [Tooltip("The number of points to generate on the parabolic line. The higher the number, the more CPU intensive the point generation becomes.")] + public int density = 10; + /// + /// The number of points along the parabolic line to check for an early cast collision. Useful if the parabolic line is appearing to clip through locations. 0 won't make any checks and it will be capped at . + /// + /// The higher the number, the more CPU intensive the checks become. + [Tooltip("The number of points along the parabolic line to check for an early cast collision. Useful if the parabolic line is appearing to clip through locations. 0 won't make any checks and it will be capped at the set density. The higher the number, the more CPU intensive the checks become.")] + public int collisionCheckFrequency; + /// + /// The amount of height offset to apply to the projected cast to generate a smoother line even when the cast is pointing straight. + /// + [Tooltip("The amount of height offset to apply to the projected cast to generate a smoother line even when the cast is pointing straight.")] + public float curveOffset = 1f; + + /// + public override void CastPoints() + { + Vector3 forward = ProjectForward(); + Vector3 down = ProjectDown(forward); + AdjustForEarlyCollisions(forward, down); + } + + /// + /// Projects a straight line forward from the current . + /// + /// The collision point or the point being the furthest away on the cast line if nothing is hit. + protected virtual Vector3 ProjectForward() + { + float rotation = Vector3.Dot(Vector3.up, transform.forward.normalized); + float length = maximumLength.x; + + if (rotation * 100f > heightLimitAngle) + { + float controllerRotationOffset = 1f - (rotation - heightLimitAngle / 100f); + length = maximumLength.x * controllerRotationOffset * controllerRotationOffset; + } + + Ray ray = new Ray(transform.position, transform.forward); + RaycastHit hitData; + bool hasCollided = PhysicsCast.Raycast(physicsCast, ray, out hitData, length, Physics.IgnoreRaycastLayer); + + // Adjust the cast length if something is blocking it. + if (hasCollided && hitData.distance < length) + { + length = hitData.distance; + } + + // Use an offset to move the point back and up a bit to prevent the cast clipping at the collision point. + return ray.GetPoint(length - ADJUSTMENT_OFFSET) + Vector3.up * ADJUSTMENT_OFFSET; + } + + /// + /// Projects a straight line downwards from the provided point. + /// + /// The origin of the projected line. + /// The collision point or the point being the furthest away on the cast line if nothing is hit. + protected virtual Vector3 ProjectDown(Vector3 origin) + { + Vector3 point = Vector3.zero; + Ray ray = new Ray(origin, Vector3.down); + RaycastHit hitData; + + bool downRayHit = PhysicsCast.Raycast(physicsCast, ray, out hitData, maximumLength.y, Physics.IgnoreRaycastLayer); + + if (!downRayHit || (TargetHit?.collider != null && TargetHit.Value.collider != hitData.collider)) + { + TargetHit = null; + point = ray.GetPoint(0f); + } + + if (downRayHit) + { + point = ray.GetPoint(hitData.distance); + TargetHit = hitData; + } + + return point; + } + + /// + /// Checks for early collisions along the parabolic line and generates the final points. + /// + /// The forward direction to use for the checks. + /// The downwards direction to use for the checks. + protected virtual void AdjustForEarlyCollisions(Vector3 forward, Vector3 down) + { + GeneratePoints(forward, down); + + collisionCheckFrequency = Mathf.Clamp(collisionCheckFrequency, 0, density); + int step = density / (collisionCheckFrequency > 0 ? collisionCheckFrequency : 1); + + for (int index = 0; index < density - step; index += step) + { + Vector3 currentPoint = points[index]; + Vector3 nextPoint = index + step < points.Count ? points[index + step] : points[points.Count - 1]; + Vector3 nextPointDirection = (nextPoint - currentPoint).normalized; + float nextPointDistance = Vector3.Distance(currentPoint, nextPoint); + + Ray pointsRay = new Ray(currentPoint, nextPointDirection); + RaycastHit pointsHitData; + + if (!PhysicsCast.Raycast(physicsCast, pointsRay, out pointsHitData, nextPointDistance, Physics.IgnoreRaycastLayer)) + { + continue; + } + + Vector3 collisionPoint = pointsRay.GetPoint(pointsHitData.distance); + Ray downwardRay = new Ray(collisionPoint + Vector3.up * 0.01f, Vector3.down); + RaycastHit downwardHitData; + + if (!PhysicsCast.Raycast(physicsCast, downwardRay, out downwardHitData, float.PositiveInfinity, Physics.IgnoreRaycastLayer)) + { + continue; + } + + TargetHit = downwardHitData; + + Vector3 newDownPosition = downwardRay.GetPoint(downwardHitData.distance); + Vector3 newJointPosition = newDownPosition.y < forward.y ? new Vector3(newDownPosition.x, forward.y, newDownPosition.z) : forward; + GeneratePoints(newJointPosition, newDownPosition); + + break; + } + + OnCastResultsChanged(); + } + + /// + /// Generates points on a parabolic line. + /// + /// The end point of the forward cast. + /// The end point of the down cast. + /// The generated points on the parabolic line. + protected virtual void GeneratePoints(Vector3 forward, Vector3 down) + { + Vector3[] curvePoints = + { + transform.position, + forward + new Vector3(0f, curveOffset, 0f), + down, + down + }; + + points.Clear(); + points.AddRange(BezierCurveGenerator.GeneratePoints(density, curvePoints)); + } + } +} diff --git a/Scripts/Cast/ParabolicLineCast.cs.meta b/Scripts/Cast/ParabolicLineCast.cs.meta new file mode 100644 index 00000000..95258a9a --- /dev/null +++ b/Scripts/Cast/ParabolicLineCast.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: f57b1a00a82f48d3a19652931fc4887d +timeCreated: 1526406952 \ No newline at end of file diff --git a/Scripts/Utility/PhysicsCast.cs b/Scripts/Cast/PhysicsCast.cs similarity index 98% rename from Scripts/Utility/PhysicsCast.cs rename to Scripts/Cast/PhysicsCast.cs index bb161fab..a95974f7 100644 --- a/Scripts/Utility/PhysicsCast.cs +++ b/Scripts/Cast/PhysicsCast.cs @@ -1,201 +1,201 @@ -namespace VRTK.Core.Utility -{ - using UnityEngine; - - /// - /// The PhysicsCast allows customising of Unity Physics casting within other scripts by applying settings at edit time. - /// - public class PhysicsCast : MonoBehaviour - { - [Tooltip("The layers to ignore when casting.")] - public LayerMask layersToIgnore = Physics.IgnoreRaycastLayer; - [Tooltip("Determines whether the cast will interact with trigger colliders.")] - public QueryTriggerInteraction triggerInteraction = QueryTriggerInteraction.UseGlobal; - - /// - /// The Raycast method is used to generate a Raycast either from the given PhysicsCast object or a default Physics.Raycast. - /// - /// The optional object with customised cast parameters. - /// The Ray to cast with. - /// The Raycast hit data. - /// The maximum length of the Raycast. - /// A layermask of layers to ignore from the Raycast. - /// Determines the trigger interaction level of the cast. - /// Returns `true` if the Raycast successfully collides with a valid object. - public static bool Raycast(PhysicsCast customCast, Ray ray, out RaycastHit hitData, float length, LayerMask ignoreLayers, QueryTriggerInteraction affectTriggers = QueryTriggerInteraction.UseGlobal) - { - if (customCast != null) - { - return customCast.CustomRaycast(ray, out hitData, length); - } - else - { - return Physics.Raycast(ray, out hitData, length, ~ignoreLayers, affectTriggers); - } - } - - /// - /// The Linecast method is used to generate a Linecast either from the given PhysicsCast object or a default Physics.Linecast. - /// - /// The optional object with customised cast parameters. - /// The world position to start the Linecast from. - /// The world position to end the Linecast at. - /// The Linecast hit data. - /// A layermask of layers to ignore from the Linecast. - /// Determines the trigger interaction level of the cast. - /// Returns `true` if the Linecast successfully collides with a valid object. - public static bool Linecast(PhysicsCast customCast, Vector3 startPosition, Vector3 endPosition, out RaycastHit hitData, LayerMask ignoreLayers, QueryTriggerInteraction affectTriggers = QueryTriggerInteraction.UseGlobal) - { - if (customCast != null) - { - return customCast.CustomLinecast(startPosition, endPosition, out hitData); - } - else - { - return Physics.Linecast(startPosition, endPosition, out hitData, ~ignoreLayers, affectTriggers); - } - } - - /// - /// The SphereCast method is used to generate a SphereCast either from the given PhysicsCast object or a default Physics.SphereCast. - /// - /// The optional object with customised cast parameters. - /// The origin point of the sphere to cast. - /// The radius of the sphere. - /// The direction into which to sweep the sphere. - /// The SphereCast hit data. - /// The max length of the sweep. - /// A layermask of layers to ignore from the SphereCast. - /// Determines the trigger interaction level of the cast. - /// Returns `true` if the SphereCast successfully collides with a valid object. - public static bool SphereCast(PhysicsCast customCast, Vector3 origin, float radius, Vector3 direction, out RaycastHit hitData, float maxDistance, LayerMask ignoreLayers, QueryTriggerInteraction affectTriggers = QueryTriggerInteraction.UseGlobal) - { - if (customCast != null) - { - return customCast.CustomSphereCast(origin, radius, direction, out hitData, maxDistance); - } - else - { - return Physics.SphereCast(origin, radius, direction, out hitData, maxDistance, ~ignoreLayers, affectTriggers); - } - } - - /// - /// The CapsuleCast method is used to generate a CapsuleCast either from the given PhysicsCast object or a default Physics.CapsuleCast. - /// - /// The optional object with customised cast parameters. - /// The center of the sphere at the start of the capsule. - /// The center of the sphere at the end of the capsule. - /// The radius of the capsule. - /// The direction into which to sweep the capsule. - /// The CapsuleCast hit data. - /// The max length of the sweep. - /// A layermask of layers to ignore from the CapsuleCast. - /// Determines the trigger interaction level of the cast. - /// Returns `true` if the CapsuleCast successfully collides with a valid object. - public static bool CapsuleCast(PhysicsCast customCast, Vector3 point1, Vector3 point2, float radius, Vector3 direction, out RaycastHit hitData, float maxDistance, LayerMask ignoreLayers, QueryTriggerInteraction affectTriggers = QueryTriggerInteraction.UseGlobal) - { - if (customCast != null) - { - return customCast.CustomCapsuleCast(point1, point2, radius, direction, out hitData, maxDistance); - } - else - { - return Physics.CapsuleCast(point1, point2, radius, direction, out hitData, maxDistance, ~ignoreLayers, affectTriggers); - } - } - - /// - /// The BoxCast method is used to generate a BoxCast either from the given PhysicsCast object or a default Physics.BoxCast. - /// - /// The optional object with customised cast parameters. - /// The center of the box. - /// Half the size of the box in each dimension. - /// The direction in which to cast the box. - /// The BoxCast hit data. - /// The rotation of the box. - /// The max length of the cast. - /// A layermask of layers to ignore from the BoxCast. - /// Determines the trigger interaction level of the cast. - /// Returns `true` if the BoxCast successfully collides with a valid object. - public static bool BoxCast(PhysicsCast customCast, Vector3 center, Vector3 halfExtents, Vector3 direction, out RaycastHit hitData, Quaternion orientation, float maxDistance, LayerMask ignoreLayers, QueryTriggerInteraction affectTriggers = QueryTriggerInteraction.UseGlobal) - { - if (customCast != null) - { - return customCast.CustomBoxCast(center, halfExtents, direction, out hitData, orientation, maxDistance); - } - else - { - return Physics.BoxCast(center, halfExtents, direction, out hitData, orientation, maxDistance, ~ignoreLayers, affectTriggers); - } - } - - /// - /// The CustomRaycast method is used to generate a Raycast based on the options defined in the PhysicsCast object. - /// - /// The Ray to cast with. - /// The Raycast hit data. - /// The maximum length of the Raycast. - /// Returns `true` if the Raycast successfully collides with a valid object. - public virtual bool CustomRaycast(Ray ray, out RaycastHit hitData, float length) - { - return Physics.Raycast(ray, out hitData, length, ~layersToIgnore, triggerInteraction); - } - - /// - /// The CustomLinecast method is used to generate a Linecast based on the options defined in the PhysicsCast object. - /// - /// The world position to start the Linecast from. - /// The world position to end the Linecast at. - /// The Linecast hit data. - /// Returns `true` if the Linecast successfully collides with a valid object. - public virtual bool CustomLinecast(Vector3 startPosition, Vector3 endPosition, out RaycastHit hitData) - { - return Physics.Linecast(startPosition, endPosition, out hitData, ~layersToIgnore, triggerInteraction); - } - - /// - /// The CustomSphereCast method is used to generate a SphereCast based on the options defined in the PhysicsCast object. - /// - /// The origin point of the sphere to cast. - /// The radius of the sphere. - /// The direction into which to sweep the sphere. - /// The SphereCast hit data. - /// The max length of the sweep. - /// Returns `true` if the SphereCast successfully collides with a valid object. - public virtual bool CustomSphereCast(Vector3 origin, float radius, Vector3 direction, out RaycastHit hitData, float maxDistance) - { - return Physics.SphereCast(origin, radius, direction, out hitData, maxDistance, ~layersToIgnore, triggerInteraction); - } - - /// - /// The CustomCapsuleCast method is used to generate a CapsuleCast based on the options defined in the PhysicsCast object. - /// - /// The center of the sphere at the start of the capsule. - /// The center of the sphere at the end of the capsule. - /// The radius of the capsule. - /// The direction into which to sweep the capsule. - /// The CapsuleCast hit data. - /// The max length of the sweep. - /// Returns `true` if the CapsuleCast successfully collides with a valid object. - public virtual bool CustomCapsuleCast(Vector3 point1, Vector3 point2, float radius, Vector3 direction, out RaycastHit hitData, float maxDistance) - { - return Physics.CapsuleCast(point1, point2, radius, direction, out hitData, maxDistance, ~layersToIgnore, triggerInteraction); - } - - /// - /// The CustomBoxCast method is used to generate a BoxCast based on the options defined in the PhysicsCast object. - /// - /// The center of the box. - /// Half the size of the box in each dimension. - /// The direction in which to cast the box. - /// The BoxCast hit data. - /// The rotation of the box. - /// The max length of the cast. - /// Returns `true` if the box successfully collides with a valid object. - public virtual bool CustomBoxCast(Vector3 center, Vector3 halfExtents, Vector3 direction, out RaycastHit hitData, Quaternion orientation, float maxDistance) - { - return Physics.BoxCast(center, halfExtents, direction, out hitData, orientation, maxDistance, ~layersToIgnore, triggerInteraction); - } - } +namespace VRTK.Core.Cast +{ + using UnityEngine; + + /// + /// The PhysicsCast allows customising of Unity Physics casting within other scripts by applying settings at edit time. + /// + public class PhysicsCast : MonoBehaviour + { + [Tooltip("The layers to ignore when casting.")] + public LayerMask layersToIgnore = Physics.IgnoreRaycastLayer; + [Tooltip("Determines whether the cast will interact with trigger colliders.")] + public QueryTriggerInteraction triggerInteraction = QueryTriggerInteraction.UseGlobal; + + /// + /// The Raycast method is used to generate a Raycast either from the given PhysicsCast object or a default Physics.Raycast. + /// + /// The optional object with customised cast parameters. + /// The Ray to cast with. + /// The Raycast hit data. + /// The maximum length of the Raycast. + /// A layermask of layers to ignore from the Raycast. + /// Determines the trigger interaction level of the cast. + /// Returns `true` if the Raycast successfully collides with a valid object. + public static bool Raycast(PhysicsCast customCast, Ray ray, out RaycastHit hitData, float length, LayerMask ignoreLayers, QueryTriggerInteraction affectTriggers = QueryTriggerInteraction.UseGlobal) + { + if (customCast != null) + { + return customCast.CustomRaycast(ray, out hitData, length); + } + else + { + return Physics.Raycast(ray, out hitData, length, ~ignoreLayers, affectTriggers); + } + } + + /// + /// The Linecast method is used to generate a Linecast either from the given PhysicsCast object or a default Physics.Linecast. + /// + /// The optional object with customised cast parameters. + /// The world position to start the Linecast from. + /// The world position to end the Linecast at. + /// The Linecast hit data. + /// A layermask of layers to ignore from the Linecast. + /// Determines the trigger interaction level of the cast. + /// Returns `true` if the Linecast successfully collides with a valid object. + public static bool Linecast(PhysicsCast customCast, Vector3 startPosition, Vector3 endPosition, out RaycastHit hitData, LayerMask ignoreLayers, QueryTriggerInteraction affectTriggers = QueryTriggerInteraction.UseGlobal) + { + if (customCast != null) + { + return customCast.CustomLinecast(startPosition, endPosition, out hitData); + } + else + { + return Physics.Linecast(startPosition, endPosition, out hitData, ~ignoreLayers, affectTriggers); + } + } + + /// + /// The SphereCast method is used to generate a SphereCast either from the given PhysicsCast object or a default Physics.SphereCast. + /// + /// The optional object with customised cast parameters. + /// The origin point of the sphere to cast. + /// The radius of the sphere. + /// The direction into which to sweep the sphere. + /// The SphereCast hit data. + /// The max length of the sweep. + /// A layermask of layers to ignore from the SphereCast. + /// Determines the trigger interaction level of the cast. + /// Returns `true` if the SphereCast successfully collides with a valid object. + public static bool SphereCast(PhysicsCast customCast, Vector3 origin, float radius, Vector3 direction, out RaycastHit hitData, float maxDistance, LayerMask ignoreLayers, QueryTriggerInteraction affectTriggers = QueryTriggerInteraction.UseGlobal) + { + if (customCast != null) + { + return customCast.CustomSphereCast(origin, radius, direction, out hitData, maxDistance); + } + else + { + return Physics.SphereCast(origin, radius, direction, out hitData, maxDistance, ~ignoreLayers, affectTriggers); + } + } + + /// + /// The CapsuleCast method is used to generate a CapsuleCast either from the given PhysicsCast object or a default Physics.CapsuleCast. + /// + /// The optional object with customised cast parameters. + /// The center of the sphere at the start of the capsule. + /// The center of the sphere at the end of the capsule. + /// The radius of the capsule. + /// The direction into which to sweep the capsule. + /// The CapsuleCast hit data. + /// The max length of the sweep. + /// A layermask of layers to ignore from the CapsuleCast. + /// Determines the trigger interaction level of the cast. + /// Returns `true` if the CapsuleCast successfully collides with a valid object. + public static bool CapsuleCast(PhysicsCast customCast, Vector3 point1, Vector3 point2, float radius, Vector3 direction, out RaycastHit hitData, float maxDistance, LayerMask ignoreLayers, QueryTriggerInteraction affectTriggers = QueryTriggerInteraction.UseGlobal) + { + if (customCast != null) + { + return customCast.CustomCapsuleCast(point1, point2, radius, direction, out hitData, maxDistance); + } + else + { + return Physics.CapsuleCast(point1, point2, radius, direction, out hitData, maxDistance, ~ignoreLayers, affectTriggers); + } + } + + /// + /// The BoxCast method is used to generate a BoxCast either from the given PhysicsCast object or a default Physics.BoxCast. + /// + /// The optional object with customised cast parameters. + /// The center of the box. + /// Half the size of the box in each dimension. + /// The direction in which to cast the box. + /// The BoxCast hit data. + /// The rotation of the box. + /// The max length of the cast. + /// A layermask of layers to ignore from the BoxCast. + /// Determines the trigger interaction level of the cast. + /// Returns `true` if the BoxCast successfully collides with a valid object. + public static bool BoxCast(PhysicsCast customCast, Vector3 center, Vector3 halfExtents, Vector3 direction, out RaycastHit hitData, Quaternion orientation, float maxDistance, LayerMask ignoreLayers, QueryTriggerInteraction affectTriggers = QueryTriggerInteraction.UseGlobal) + { + if (customCast != null) + { + return customCast.CustomBoxCast(center, halfExtents, direction, out hitData, orientation, maxDistance); + } + else + { + return Physics.BoxCast(center, halfExtents, direction, out hitData, orientation, maxDistance, ~ignoreLayers, affectTriggers); + } + } + + /// + /// The CustomRaycast method is used to generate a Raycast based on the options defined in the PhysicsCast object. + /// + /// The Ray to cast with. + /// The Raycast hit data. + /// The maximum length of the Raycast. + /// Returns `true` if the Raycast successfully collides with a valid object. + public virtual bool CustomRaycast(Ray ray, out RaycastHit hitData, float length) + { + return Physics.Raycast(ray, out hitData, length, ~layersToIgnore, triggerInteraction); + } + + /// + /// The CustomLinecast method is used to generate a Linecast based on the options defined in the PhysicsCast object. + /// + /// The world position to start the Linecast from. + /// The world position to end the Linecast at. + /// The Linecast hit data. + /// Returns `true` if the Linecast successfully collides with a valid object. + public virtual bool CustomLinecast(Vector3 startPosition, Vector3 endPosition, out RaycastHit hitData) + { + return Physics.Linecast(startPosition, endPosition, out hitData, ~layersToIgnore, triggerInteraction); + } + + /// + /// The CustomSphereCast method is used to generate a SphereCast based on the options defined in the PhysicsCast object. + /// + /// The origin point of the sphere to cast. + /// The radius of the sphere. + /// The direction into which to sweep the sphere. + /// The SphereCast hit data. + /// The max length of the sweep. + /// Returns `true` if the SphereCast successfully collides with a valid object. + public virtual bool CustomSphereCast(Vector3 origin, float radius, Vector3 direction, out RaycastHit hitData, float maxDistance) + { + return Physics.SphereCast(origin, radius, direction, out hitData, maxDistance, ~layersToIgnore, triggerInteraction); + } + + /// + /// The CustomCapsuleCast method is used to generate a CapsuleCast based on the options defined in the PhysicsCast object. + /// + /// The center of the sphere at the start of the capsule. + /// The center of the sphere at the end of the capsule. + /// The radius of the capsule. + /// The direction into which to sweep the capsule. + /// The CapsuleCast hit data. + /// The max length of the sweep. + /// Returns `true` if the CapsuleCast successfully collides with a valid object. + public virtual bool CustomCapsuleCast(Vector3 point1, Vector3 point2, float radius, Vector3 direction, out RaycastHit hitData, float maxDistance) + { + return Physics.CapsuleCast(point1, point2, radius, direction, out hitData, maxDistance, ~layersToIgnore, triggerInteraction); + } + + /// + /// The CustomBoxCast method is used to generate a BoxCast based on the options defined in the PhysicsCast object. + /// + /// The center of the box. + /// Half the size of the box in each dimension. + /// The direction in which to cast the box. + /// The BoxCast hit data. + /// The rotation of the box. + /// The max length of the cast. + /// Returns `true` if the box successfully collides with a valid object. + public virtual bool CustomBoxCast(Vector3 center, Vector3 halfExtents, Vector3 direction, out RaycastHit hitData, Quaternion orientation, float maxDistance) + { + return Physics.BoxCast(center, halfExtents, direction, out hitData, orientation, maxDistance, ~layersToIgnore, triggerInteraction); + } + } } \ No newline at end of file diff --git a/Scripts/Utility/PhysicsCast.cs.meta b/Scripts/Cast/PhysicsCast.cs.meta similarity index 100% rename from Scripts/Utility/PhysicsCast.cs.meta rename to Scripts/Cast/PhysicsCast.cs.meta diff --git a/Scripts/Cast/PointsCast.cs b/Scripts/Cast/PointsCast.cs new file mode 100644 index 00000000..06166b31 --- /dev/null +++ b/Scripts/Cast/PointsCast.cs @@ -0,0 +1,107 @@ +namespace VRTK.Core.Cast +{ + using UnityEngine; + using UnityEngine.Events; + using System; + using System.Collections.Generic; + using VRTK.Core.Process; + using VRTK.Core.Utility; + + /// + /// Contains information about the current state. + /// + public class PointsCastData + { + /// + /// The result of the most recent cast. when the cast didn't hit anything. + /// + public RaycastHit? targetHit; + /// + /// The points along the the most recent cast. + /// + public IReadOnlyList points; + } + + /// + /// The base of casting components that result in points along the cast. + /// + public abstract class PointsCast : MonoBehaviour, IProcessable + { + /// + /// Allows to optionally affect the cast. + /// + [Tooltip("Allows to optionally affect the cast.")] + public PhysicsCast physicsCast; + /// + /// Allows to optionally determine targets based on the set rules. + /// + [Tooltip("Allows to optionally determine targets based on the set rules.")] + public ExclusionRule targetValidity; + + /// + /// Defines the event with the state and sender . + /// + [Serializable] + public class PointsCastUnityEvent : UnityEvent + { + } + + /// + /// Emitted whenever the cast result changes. + /// + public PointsCastUnityEvent CastResultsChanged = new PointsCastUnityEvent(); + + /// + /// The result of the most recent cast. when the cast didn't hit anything or an invalid target according to . + /// + public RaycastHit? TargetHit + { + get + { + return targetHit; + } + protected set + { + targetHit = value != null && !ExclusionRule.ShouldExclude(value.Value.transform.gameObject, targetValidity) ? value : null; + } + } + + /// + /// The points along the the most recent cast. + /// + public IReadOnlyList Points => points; + + protected List points = new List(); + + private RaycastHit? targetHit; + + /// + /// Casts and creates points along the cast. + /// + public abstract void CastPoints(); + + /// + public void Process() + { + CastPoints(); + } + + /// + /// Builds the event payload for the current state of the cast. + /// + /// The current state of the cast. + protected virtual PointsCastData GetPayload() + { + return new PointsCastData + { + targetHit = TargetHit, + points = Points + }; + } + + protected virtual void OnCastResultsChanged() + { + CastResultsChanged?.Invoke(GetPayload(), this); + } + } +} \ No newline at end of file diff --git a/Scripts/Cast/PointsCast.cs.meta b/Scripts/Cast/PointsCast.cs.meta new file mode 100644 index 00000000..c9728400 --- /dev/null +++ b/Scripts/Cast/PointsCast.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 8c527ebb1902401b89088eb9c8e627df +timeCreated: 1526406894 \ No newline at end of file diff --git a/Scripts/Cast/StraightLineCast.cs b/Scripts/Cast/StraightLineCast.cs new file mode 100644 index 00000000..ff67d744 --- /dev/null +++ b/Scripts/Cast/StraightLineCast.cs @@ -0,0 +1,37 @@ +namespace VRTK.Core.Cast +{ + using UnityEngine; + using System.Linq; + + /// + /// Casts a straight line and creates points at the origin and target. + /// + public class StraightLineCast : PointsCast + { + /// + /// The maximum length to cast. + /// + [Tooltip("The maximum length to cast.")] + public float maximumLength = 100f; + + protected virtual void Awake() + { + points.Clear(); + points.AddRange(Enumerable.Repeat(Vector3.zero, 2)); + } + + /// + public override void CastPoints() + { + Ray ray = new Ray(transform.position, transform.forward); + RaycastHit hitData; + bool hasCollided = PhysicsCast.Raycast(physicsCast, ray, out hitData, maximumLength, Physics.IgnoreRaycastLayer); + TargetHit = hasCollided ? hitData : (RaycastHit?)null; + + points[0] = transform.position; + points[1] = hasCollided ? hitData.point : transform.position + transform.forward * maximumLength; + + OnCastResultsChanged(); + } + } +} \ No newline at end of file diff --git a/Scripts/Cast/StraightLineCast.cs.meta b/Scripts/Cast/StraightLineCast.cs.meta new file mode 100644 index 00000000..7fec7946 --- /dev/null +++ b/Scripts/Cast/StraightLineCast.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7934e9d7f2f8434c9358d4d4e8a14b6a +timeCreated: 1526406940 \ No newline at end of file diff --git a/Scripts/Pointer.meta b/Scripts/Pointer.meta new file mode 100644 index 00000000..ce99db63 --- /dev/null +++ b/Scripts/Pointer.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2a8115f519a29a948b2df09b1e703d7a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Pointer/Pointer.cs b/Scripts/Pointer/Pointer.cs new file mode 100644 index 00000000..f51f71ed --- /dev/null +++ b/Scripts/Pointer/Pointer.cs @@ -0,0 +1,175 @@ +namespace VRTK.Core.Pointer +{ + using UnityEngine; + using UnityEngine.Events; + using System; + using VRTK.Core.Cast; + using VRTK.Core.Data.Type; + + /// + /// Contains information about the current state. + /// + public class PointerData : SurfaceData + { + /// + /// Whether the pointer is currently hovering over a target. + /// + public bool isHovering; + /// + /// The duration that the pointer has been hovering over it's current target. + /// + public float hoverDuration; + /// + /// The points cast data generated by the pointer's . + /// + public PointsCastData pointsCastData; + } + + /// + /// Allows pointing at objects and notifies when a target is hit, continues to be hit or stops being hit by listening to a . + /// + public class Pointer : MonoBehaviour + { + /// + /// The source of hit information about the current target. + /// + public PointsCast pointsCast; + + /// + /// Defines the event with the state and sender . + /// + [Serializable] + public class PointerUnityEvent : UnityEvent + { + } + + /// + /// Emitted when the pointer collides with a new target. + /// + public PointerUnityEvent Entered = new PointerUnityEvent(); + /// + /// Emitted when the pointer stops colliding with an existing target. + /// + public PointerUnityEvent Exited = new PointerUnityEvent(); + /// + /// Emitted when the pointer changes its hovering position over an existing target. + /// + public PointerUnityEvent Hovering = new PointerUnityEvent(); + + /// + /// Reports hover duration of the pointer over the current target. + /// + public float HoverDuration + { + get; + protected set; + } + + /// + /// Whether the pointer is currently hovering over a target. + /// + /// if the pointer is currently hovering over a target, otherwise. + public bool IsHovering => HoverDuration > 0f; + + protected PointsCastData previousPointsCastData; + + /// + /// The current state of the pointer. + /// + /// A object if the pointer is currently hitting a target, otherwise. + public PointerData GetCurrentState() + { + return previousPointsCastData == null ? null : GetPayload(previousPointsCastData); + } + + protected virtual void OnEnable() + { + pointsCast.CastResultsChanged.AddListener(CastResultsChanged); + } + + protected virtual void OnDisable() + { + pointsCast.CastResultsChanged.RemoveListener(CastResultsChanged); + } + + /// + /// Handles the provided data to transition state and emit the pointer events. + /// + /// The data describing the results of the most recent cast. + /// The object from which was retrieved from. + protected virtual void CastResultsChanged(PointsCastData data, object sender) + { + if (data.targetHit != null) + { + Transform targetTransform = data.targetHit.Value.transform; + if (targetTransform != null && targetTransform != previousPointsCastData?.targetHit?.transform) + { + TryEmitExit(data); + OnEntered(data); + } + + HoverDuration += Time.deltaTime; + OnHovering(data); + } + else + { + TryEmitExit(data); + } + + previousPointsCastData = data; + } + + /// + /// Checks to see if the pointer is not currently colliding with a valid target and emits the event. + /// + /// The current points cast data. + protected virtual void TryEmitExit(PointsCastData data) + { + if (previousPointsCastData?.targetHit?.transform == null) + { + return; + } + + HoverDuration = 0f; + OnExited(data); + previousPointsCastData = null; + } + + /// + /// Builds a valid pointer payload to use in the events. + /// + /// A object of the pointer's current state. + protected virtual PointerData GetPayload(PointsCastData data) + { + Transform targetTransform = pointsCast.TargetHit?.transform; + return new PointerData + { + transform = transform, + positionOverride = targetTransform == null ? (Vector3?)null : targetTransform.position, + rotationOverride = targetTransform == null ? (Quaternion?)null : targetTransform.localRotation, + localScaleOverride = targetTransform == null ? (Vector3?)null : targetTransform.localScale, + origin = transform.position, + direction = transform.forward, + CollisionData = pointsCast.TargetHit ?? default(RaycastHit), + isHovering = IsHovering, + hoverDuration = HoverDuration, + pointsCastData = data + }; + } + + protected virtual void OnEntered(PointsCastData data) + { + Entered?.Invoke(GetPayload(data), this); + } + + protected virtual void OnExited(PointsCastData data) + { + Exited?.Invoke(GetPayload(data), this); + } + + protected virtual void OnHovering(PointsCastData data) + { + Hovering?.Invoke(GetPayload(data), this); + } + } +} \ No newline at end of file diff --git a/Scripts/Pointer/Pointer.cs.meta b/Scripts/Pointer/Pointer.cs.meta new file mode 100644 index 00000000..7250722d --- /dev/null +++ b/Scripts/Pointer/Pointer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5195ecf61608495884b10998b2c6d117 +timeCreated: 1526406779 \ No newline at end of file diff --git a/Scripts/Pointer/PointerSelection.cs b/Scripts/Pointer/PointerSelection.cs new file mode 100644 index 00000000..f1563023 --- /dev/null +++ b/Scripts/Pointer/PointerSelection.cs @@ -0,0 +1,26 @@ +namespace VRTK.Core.Pointer +{ + using UnityEngine; + + /// + /// Adds the concept of selection to a . + /// + public class PointerSelection : MonoBehaviour + { + public Pointer pointer; + + /// + /// Emitted whenever is called. + /// + public Pointer.PointerUnityEvent Selected = new Pointer.PointerUnityEvent(); + + /// + /// Gets the current pointer state and emits it. + /// + /// The emitted pointer state is in case the pointer isn't hitting any target. + public virtual void Select() + { + Selected?.Invoke(pointer.GetCurrentState(), this); + } + } +} \ No newline at end of file diff --git a/Scripts/Pointer/PointerSelection.cs.meta b/Scripts/Pointer/PointerSelection.cs.meta new file mode 100644 index 00000000..69a4e30f --- /dev/null +++ b/Scripts/Pointer/PointerSelection.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: db0b134eb27b4e74a71ed8c651efb2b9 +timeCreated: 1526406886 \ No newline at end of file diff --git a/Scripts/Tracking/SurfaceLocator.cs b/Scripts/Tracking/SurfaceLocator.cs index 491e92da..3883f2d5 100644 --- a/Scripts/Tracking/SurfaceLocator.cs +++ b/Scripts/Tracking/SurfaceLocator.cs @@ -3,6 +3,7 @@ using UnityEngine; using UnityEngine.Events; using System; + using VRTK.Core.Cast; using VRTK.Core.Utility; using VRTK.Core.Data.Type; using VRTK.Core.Process; diff --git a/Scripts/Utility/BezierCurveGenerator.cs b/Scripts/Utility/BezierCurveGenerator.cs new file mode 100644 index 00000000..ea322a63 --- /dev/null +++ b/Scripts/Utility/BezierCurveGenerator.cs @@ -0,0 +1,52 @@ +namespace VRTK.Core.Utility +{ + using UnityEngine; + using System.Collections.Generic; + + /// + /// A collection of helper methods generating points on a bezier curve. + /// + public static class BezierCurveGenerator + { + /// + /// Generates points on a bezier curve. + /// + /// The number of points to generate. + /// Points defining the bezier curve. + /// The generated points. + public static Vector3[] GeneratePoints(int count, Vector3[] controlPoints) + { + Vector3[] calculatedPoints = new Vector3[count]; + float stepSize = count != 1 ? 1f / (count - 1) : count; + + for (int f = 0; f < count; f++) + { + calculatedPoints[f] = GeneratePoint(controlPoints, f * stepSize); + } + + return calculatedPoints; + } + + private static Vector3 GeneratePoint(IReadOnlyList controlPoints, float t) + { + int index; + if (t >= 1f) + { + t = 1f; + index = controlPoints.Count - 4; + } + else + { + t = Mathf.Clamp01(t) * ((controlPoints.Count - 1) / 3f); + index = (int)t; + t -= index; + index *= 3; + } + + float t1 = t; + t1 = Mathf.Clamp01(t1); + float oneMinusT = 1f - t1; + return oneMinusT * oneMinusT * oneMinusT * controlPoints[index] + 3f * oneMinusT * oneMinusT * t1 * controlPoints[index + 1] + 3f * oneMinusT * t1 * t1 * controlPoints[index + 2] + t1 * t1 * t1 * controlPoints[index + 3]; + } + } +} diff --git a/Scripts/Utility/BezierCurveGenerator.cs.meta b/Scripts/Utility/BezierCurveGenerator.cs.meta new file mode 100644 index 00000000..e326d7da --- /dev/null +++ b/Scripts/Utility/BezierCurveGenerator.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a17fd115e2a54dbeb58716bc64cb8c7c +timeCreated: 1526417342 \ No newline at end of file diff --git a/Scripts/Utility/TransformExtensions.cs b/Scripts/Utility/TransformExtensions.cs new file mode 100644 index 00000000..b56c20ca --- /dev/null +++ b/Scripts/Utility/TransformExtensions.cs @@ -0,0 +1,18 @@ +namespace VRTK.Core.Utility +{ + using UnityEngine; + + public static class TransformExtensions + { + /// + /// The SetGlobalScale method is used to set a transform scale based on a global scale instead of a local scale. + /// + /// The reference to the transform to scale. + /// A Vector3 of a global scale to apply to the given transform. + public static void SetGlobalScale(this Transform transform, Vector3 globalScale) + { + transform.localScale = Vector3.one; + transform.localScale = new Vector3(globalScale.x / transform.lossyScale.x, globalScale.y / transform.lossyScale.y, globalScale.z / transform.lossyScale.z); + } + } +} diff --git a/Scripts/Utility/TransformExtensions.cs.meta b/Scripts/Utility/TransformExtensions.cs.meta new file mode 100644 index 00000000..4af8e183 --- /dev/null +++ b/Scripts/Utility/TransformExtensions.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a54e9605dd1c416e8f50e7e6943e3f9a +timeCreated: 1526738386 \ No newline at end of file diff --git a/Scripts/Visual/PointsRenderer.cs b/Scripts/Visual/PointsRenderer.cs new file mode 100644 index 00000000..46f8d494 --- /dev/null +++ b/Scripts/Visual/PointsRenderer.cs @@ -0,0 +1,261 @@ +namespace VRTK.Core.Visual +{ + using UnityEngine; + using System; + using System.Collections.Generic; + using VRTK.Core.Cast; + using VRTK.Core.Utility; + + public class PointsRenderer : MonoBehaviour + { + /// + /// The visibility of the pointer elements. + /// + public enum Visibility + { + /// + /// The element will only be visible when the pointer is in the active and enabled state. + /// + OnWhenActiveAndEnabled, + /// + /// The element will always be visible regardless of the pointer state. + /// + AlwaysOn, + /// + /// The element will never be visible regardless of the pointer state. + /// + AlwaysOff + } + + [Serializable] + public class Element + { + /// + /// The to represent the element when the pointer is colliding with a valid object. + /// + [Tooltip("The GameObject to represent the element when the pointer is colliding with a valid object.")] + public GameObject validObject; + /// + /// The to represent the element when the pointer is colliding with an invalid object or not colliding at all. + /// + [Tooltip("The GameObject to represent the element when the pointer is colliding with an invalid object or not colliding at all.")] + public GameObject invalidObject; + /// + /// Determines when the element should be seen. + /// + [Tooltip("Determines when the element GameObject should be seen.")] + public Visibility visibility = Visibility.OnWhenActiveAndEnabled; + } + + /// + /// The from which the points to render will be taken from. + /// + [Tooltip("The PointsCast from which the points to render will be taken from.")] + public PointsCast pointsCast; + + /// + /// The direction to scale the s in. Set axes to 0 to disable scaling on that axis. + /// + [Tooltip("The direction to scale the Elements in. Set axes to 0 to disable scaling on that axis.")] + public Vector3 scaleDirection = Vector3.forward; + + /// + /// The to represent the pointer's tracer. + /// + [Tooltip("The Element to represent the pointer's tracer.")] + public Element tracer; + /// + /// The to represent the pointer's optional middle. + /// + [Tooltip("The Element to represent the pointer's optional middle.")] + public Element middle; + /// + /// The to represent the pointer's cursor. + /// + [Tooltip("The Element to represent the pointer's cursor.")] + public Element cursor; + + protected readonly List validMiddleClones = new List(); + protected readonly List invalidMiddleClones = new List(); + + protected virtual void OnEnable() + { + pointsCast.CastResultsChanged.AddListener(CastResultsChanged); + } + + protected virtual void OnDisable() + { + pointsCast.CastResultsChanged.RemoveListener(CastResultsChanged); + + foreach (List gameObjects in new[] + { + validMiddleClones, + invalidMiddleClones + }) + { + gameObjects.ForEach(Destroy); + gameObjects.Clear(); + } + + foreach (GameObject @object in new[] + { + tracer.validObject, + tracer.invalidObject, + cursor.validObject, + cursor.invalidObject + }) + { + @object.SetActive(false); + } + } + + protected virtual void CastResultsChanged(PointsCastData data, object sender) + { + UpdateNumberOfClones(data); + UpdateElements(); + } + + /// + /// Ensures the number of cloned elements matches the provided number of points. + /// + /// The points data to create cloned elements for. + protected virtual void UpdateNumberOfClones(PointsCastData data) + { + int targetCount = data.points.Count - 1; + foreach (List gameObjects in new[] + { + validMiddleClones, + invalidMiddleClones + }) + { + for (int index = gameObjects.Count - 1; index >= targetCount; index--) + { + Destroy(gameObjects[index]); + gameObjects.RemoveAt(index); + } + } + + if (middle.validObject != null) + { + for (int index = validMiddleClones.Count; index < targetCount; index++) + { + validMiddleClones.Add(Instantiate(middle.validObject, middle.validObject.transform.parent)); + } + } + + if (middle.invalidObject != null) + { + for (int index = invalidMiddleClones.Count; index < targetCount; index++) + { + invalidMiddleClones.Add(Instantiate(middle.invalidObject, middle.invalidObject.transform.parent)); + } + } + } + + /// + /// Updates all elements. + /// + protected virtual void UpdateElements() + { + UpdateElement(0, false, tracer.visibility, tracer.validObject, tracer.invalidObject); + UpdateElement(pointsCast.Points.Count - 1, false, cursor.visibility, cursor.validObject, cursor.invalidObject); + + if (middle.validObject != null) + { + middle.validObject.SetActive(false); + } + + if (middle.invalidObject != null) + { + middle.invalidObject.SetActive(false); + } + + for (int index = 0; index < validMiddleClones.Count; index++) + { + UpdateElement(index, true, middle.visibility, validMiddleClones[index], invalidMiddleClones[index]); + } + } + + /// + /// Updates the element for a specific point. + /// + /// The index of the point that is represented by the element. + /// Whether the element is part of the line or alternatively it's representing a point. + /// The visibility of the element. + /// The valid representation of the element. + /// The invalid representation of the element. + protected virtual void UpdateElement(int pointsIndex, bool isPartOfLine, Visibility visibility, GameObject validObject, GameObject invalidObject) + { + IReadOnlyList points = pointsCast.Points; + int pointsCount = points.Count; + if (0 > pointsIndex || pointsIndex >= pointsCount) + { + return; + } + + bool isPartOfPoint = !isPartOfLine && (pointsIndex == 0 || pointsIndex == pointsCount - 1); + + Vector3 targetPoint = points[pointsIndex]; + Vector3 otherPoint = pointsIndex + 1 < pointsCount ? points[pointsIndex + 1] : points[pointsIndex - 1]; + Vector3 direction = otherPoint - targetPoint; + Vector3 position = isPartOfPoint ? targetPoint : targetPoint + 0.5f * direction; + float scaleTarget = Mathf.Abs(Vector3.Distance(targetPoint, otherPoint)) * (pointsIndex == 0 && isPartOfLine && pointsCount == 2 ? 1f : 0.5f); + + bool isElementActive = IsElementVisible(visibility) && pointsCast.TargetHit != null; + validObject.SetActive(isElementActive); + invalidObject.SetActive(!isElementActive); + + foreach (GameObject @object in new[] + { + validObject, + invalidObject + }) + { + @object.transform.position = position; + + if (isPartOfPoint) + { + continue; + } + + Vector3 scale = @object.transform.lossyScale; + + for (int index = 0; index < 3; index++) + { + if (Math.Abs(scaleDirection[index]) >= float.Epsilon) + { + scale[index] = scaleDirection[index] * scaleTarget; + } + } + + @object.transform.SetGlobalScale(scale); + @object.transform.rotation = Quaternion.LookRotation(direction); + } + } + + /// + /// Whether a given is considered visible. + /// + /// The to check for. + /// if is considered visible, otherwise . + protected virtual bool IsElementVisible(Visibility visibility) + { + if (!isActiveAndEnabled) + { + return false; + } + + switch (visibility) + { + case Visibility.OnWhenActiveAndEnabled: + return pointsCast.isActiveAndEnabled; + case Visibility.AlwaysOn: + return true; + case Visibility.AlwaysOff: + return false; + default: + throw new ArgumentOutOfRangeException(nameof(visibility), visibility, null); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Visual/PointsRenderer.cs.meta b/Scripts/Visual/PointsRenderer.cs.meta new file mode 100644 index 00000000..0945c50e --- /dev/null +++ b/Scripts/Visual/PointsRenderer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 255407672fbf4289a8950abfa476e0b0 +timeCreated: 1526406857 \ No newline at end of file