Skip to content

Commit 4b9ac44

Browse files
author
Julia Schwarz
committed
Implement fix, which moves from a cone check to a real FOV check. Still has some debugging code.
1 parent f770f8b commit 4b9ac44

File tree

6 files changed

+53
-27
lines changed

6 files changed

+53
-27
lines changed

Assets/MixedRealityToolkit.SDK/Features/UX/Scripts/Pointers/PokePointer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ private bool FindClosestTouchableForLayerMask(LayerMask layerMask, out BaseNearI
210210
var touchable = collider.GetComponent<BaseNearInteractionTouchable>();
211211
if (touchable)
212212
{
213-
if (IgnoreCollidersNotInFOV && !mainCam.IsInFOVConeCached(collider))
213+
if (IgnoreCollidersNotInFOV && !mainCam.IsInFOVCached(collider))
214214
{
215215
continue;
216216
}

Assets/MixedRealityToolkit.SDK/Features/UX/Scripts/Pointers/SpherePointer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ public bool TryUpdateQueryBufferForLayerMask(LayerMask layerMask, Vector3 pointe
290290
{
291291
if (ignoreCollidersNotInFOV)
292292
{
293-
if (!mainCam.IsInFOVConeCached(collider))
293+
if (!mainCam.IsInFOVCached(collider))
294294
{
295295
// Additional check: is grabbable in the camera frustrum
296296
// We do this so that if grabbable is not visible it is not accidentally grabbed

Assets/MixedRealityToolkit.Tests/EditModeTests/Core/Extensions/CameraExtensionTests.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -116,12 +116,12 @@ public void TearDown()
116116
/// Test that the Camera extension method IsInFOVConeCached returns valid results for colliders whose bounds are renderable to the camera
117117
/// </summary>
118118
[Test]
119-
public void TestIsInFOVConeCached()
119+
public void TestIsInFOVCached()
120120
{
121121
for (int i = 0; i < TestColliders.Count; i++)
122122
{
123123
var test = TestColliders[i];
124-
Assert.AreEqual(test.ShouldBeInFOVCamera1, testCamera.IsInFOVConeCached(test.Collider), $"TestCollider[{i}] did not match");
124+
Assert.AreEqual(test.ShouldBeInFOVCamera1, testCamera.IsInFOVCached(test.Collider), $"TestCollider[{i}] did not match");
125125
}
126126
}
127127

@@ -130,13 +130,13 @@ public void TestIsInFOVConeCached()
130130
/// facing different directions.
131131
/// </summary>
132132
[Test]
133-
public void TestIsInFOVConeCachedSecondCamera()
133+
public void TestIsInFOVCachedSecondCamera()
134134
{
135135
for (int i = 0; i < TestColliders.Count; i++)
136136
{
137137
var test = TestColliders[i];
138-
Assert.AreEqual(test.ShouldBeInFOVCamera1, testCamera.IsInFOVConeCached(test.Collider), $"TestCollider[{i}] did not match");
139-
Assert.AreEqual(test.ShouldBeInFOVCamera2, testCamera2.IsInFOVConeCached(test.Collider), $"TestColliderSecondCamera[{i}] did not match");
138+
Assert.AreEqual(test.ShouldBeInFOVCamera1, testCamera.IsInFOVCached(test.Collider), $"TestCollider[{i}] did not match");
139+
Assert.AreEqual(test.ShouldBeInFOVCamera2, testCamera2.IsInFOVCached(test.Collider), $"TestColliderSecondCamera[{i}] did not match");
140140
}
141141
}
142142

Assets/MixedRealityToolkit.Tests/PlayModeTests/PointerTests.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ public IEnumerator TestPointerFieldOfViewLargeCollider()
130130

131131
private IEnumerator TestPointerFieldOfViewLargeColliderHelper(IMixedRealityPointer myPointer, GameObject cube, TestHand testHand)
132132
{
133-
cube.transform.localScale = new Vector3(1, 1, 0.05f);
133+
cube.transform.localScale = new Vector3(3, 3, 0.05f);
134134
float[] yOffsets = new float[] { -1f, 0f, 1f };
135135
float[] xOffsets = new float[] { -1f, 0f, 1f };
136136
float[] zOffsets = new float[] { 1f, -1f };
@@ -144,11 +144,12 @@ private IEnumerator TestPointerFieldOfViewLargeColliderHelper(IMixedRealityPoint
144144
var cameraPos = CameraCache.Main.transform.position;
145145
var pos = new Vector3(cameraPos.x + xOffset, cameraPos.y + yOffset, cameraPos.z + zOffset);
146146
cube.transform.position = pos;
147-
cube.transform.LookAt(CameraCache.Main.transform);
148147
yield return testHand.MoveTo(cube.transform.position);
149148
yield return PlayModeTestUtilities.WaitForInputSystemUpdate();
149+
yield return PlayModeTestUtilities.WaitForEnterKey();
150+
bool isInFov = CameraCache.Main.IsInFOVCached(cube.GetComponent<BoxCollider>());
150151
Assert.IsTrue(zOffset == 1f ? myPointer.IsInteractionEnabled : !myPointer.IsInteractionEnabled,
151-
$"Pointer {myPointer.PointerName} in incorrect state. Cube size {cube.transform.localScale} location {cube.transform.position}.");
152+
$"Pointer {myPointer.PointerName} in incorrect state. IsInFOV {isInFov} Cube size {cube.transform.localScale} location {cube.transform.position}.");
152153
}
153154
}
154155
}
@@ -218,6 +219,7 @@ private IEnumerator TestPointerFieldOfViewHelper(IMixedRealityPointer myPointer,
218219
yield return PlayModeTestUtilities.WaitForInputSystemUpdate();
219220
Assert.IsTrue(myPointer.IsInteractionEnabled, $"Pointer {myPointer.PointerName} should be enabled because it is near object inside of FOV. Cube size {cube.transform.localScale} location {cube.transform.position}.");
220221
}
222+
221223
/// <summary>
222224
/// Tests that sphere pointer grabs object when hand is inside a giant grabbable
223225
/// </summary>

Assets/MixedRealityToolkit/Utilities/CameraFOVChecker.cs

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,23 @@ public static class CameraFOVChecker
2727
/// <summary>
2828
/// Returns true if a collider's bounds is within the camera FOV.
2929
/// Utilizes a cache to test if this collider has been seen before and returns current frame's calculated result.
30+
/// NOTE: This is a 'loose' FOV check -- it can return true in cases when the collider is actually not in the FOV
31+
/// because it does an axis-aligned check. So, if the axis aligned bounds are in the bounds of the camera, it will return true.
3032
/// </summary>
3133
/// <param name="myCollider">The collider to test</param>
32-
public static bool IsInFOVConeCached(this Camera cam,
33-
Collider myCollider)
34+
public static bool IsInFOVCached(this Camera cam,
35+
Collider myCollider, bool debug=false)
3436
{
37+
if(debug)
38+
{
39+
Debug.Log("debugging");
40+
}
3541
// if the collider's size is zero, it is not visible. Return false.
36-
if(myCollider.bounds.size == Vector3.zero || myCollider.transform.localScale == Vector3.zero)
42+
if (myCollider.bounds.size == Vector3.zero || myCollider.transform.localScale == Vector3.zero)
3743
{
3844
return false;
3945
}
40-
46+
4147
Tuple<Collider, Camera> cameraColliderPair = new Tuple<Collider, Camera>(myCollider, cam);
4248
bool result = false;
4349
if (inFOVConeLastCalculatedFrame != Time.frameCount)
@@ -46,37 +52,50 @@ public static bool IsInFOVConeCached(this Camera cam,
4652
inFOVConeLastCalculatedFrame = Time.frameCount;
4753
}
4854
else if (inFOVConeColliderCache.TryGetValue(cameraColliderPair, out result))
49-
{
55+
{
5056
return result;
5157
}
5258

5359
inFOVConeBoundsCornerPoints.Clear();
5460
BoundsExtensions.GetColliderBoundsPoints(myCollider, inFOVConeBoundsCornerPoints, 0);
5561

62+
5663
float xMin = float.MaxValue, yMin = float.MaxValue, zMin = float.MaxValue;
5764
float xMax = float.MinValue, yMax = float.MinValue, zMax = float.MinValue;
5865
for (int i = 0; i < inFOVConeBoundsCornerPoints.Count; i++)
5966
{
6067
var corner = inFOVConeBoundsCornerPoints[i];
6168
if (cam.IsInFOVCone(corner, 0))
6269
{
70+
if(debug)
71+
{
72+
Debug.Log("IsInFOVCone returned true");
73+
}
6374
inFOVConeColliderCache.Add(cameraColliderPair, true);
6475
return true;
6576
}
6677

67-
xMin = Mathf.Min(xMin, corner.x);
68-
yMin = Mathf.Min(yMin, corner.y);
69-
zMin = Mathf.Min(zMin, corner.z);
70-
xMax = Mathf.Max(xMax, corner.x);
71-
yMax = Mathf.Max(yMax, corner.y);
72-
zMax = Mathf.Max(zMax, corner.z);
78+
var cornerScreen = cam.WorldToScreenPoint(corner);
79+
xMin = Mathf.Min(xMin, cornerScreen.x);
80+
yMin = Mathf.Min(yMin, cornerScreen.y);
81+
zMin = Mathf.Min(zMin, cornerScreen.z);
82+
xMax = Mathf.Max(xMax, cornerScreen.x);
83+
yMax = Mathf.Max(yMax, cornerScreen.y);
84+
zMax = Mathf.Max(zMax, cornerScreen.z);
7385
}
7486

75-
var cameraPos = cam.transform.position;
76-
result = xMin <= cameraPos.x && cameraPos.x <= xMax
77-
&& yMin <= cameraPos.y && cameraPos.y <= yMax
78-
&& zMin <= cameraPos.z && cameraPos.z <= zMax;
79-
87+
// case 1
88+
result =
89+
zMax > 0 // in front of the camera
90+
&& zMin < cam.farClipPlane // not too far
91+
&& xMin < cam.pixelWidth // left edge is not too far over
92+
&& xMax > 0 // right edge is not too far over
93+
&& yMin < cam.pixelHeight // bottom edge is not too high
94+
&& yMax > 0; // top edge is not too high
95+
if (debug)
96+
{
97+
Debug.Log($"{myCollider.gameObject.name} {xMin}, {xMax}, {yMin}, {yMax}, {zMin}, {zMax} {cam.nearClipPlane} {cam.farClipPlane} {cam.pixelWidth} {cam.pixelHeight} {result}");
98+
}
8099
inFOVConeColliderCache.Add(cameraColliderPair, result);
81100

82101
return result;

Assets/MixedRealityToolkit/Utilities/MathUtilities.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -532,7 +532,8 @@ public static bool IsInFOVCone(Transform cone,
532532
Vector3 point,
533533
float fieldOfView,
534534
float minDist = 0.05f,
535-
float maxDist = 100f)
535+
float maxDist = 100f,
536+
bool debug = false)
536537
{
537538
var dirToPoint = point - cone.position;
538539

@@ -543,6 +544,10 @@ public static bool IsInFOVCone(Transform cone,
543544
}
544545

545546
var degrees = Mathf.Acos(pointDist / dirToPoint.magnitude) * Mathf.Rad2Deg;
547+
if (debug)
548+
{
549+
Debug.Log($"degrees: {degrees} fov: {fieldOfView} pointDist: {pointDist}");
550+
}
546551
return degrees < fieldOfView * 0.5f;
547552
}
548553

0 commit comments

Comments
 (0)