internal (SCNVector3?, ARPlaneAnchor, Boolean) WorldPositionFromScreenPosition(CGPoint position, ARSCNView sceneView, SCNVector3?objectPos, bool infinitePlane = false) { var dragOnInfinitePlanesEnabled = AppSettings.DragOnInfinitePlanes; // ------------------------------------------------------------------------------- // 1. Always do a hit test against exisiting plane anchors first. // (If any such anchors exist & only within their extents.) var planeHitTestResults = sceneView.HitTest(position, ARHitTestResultType.ExistingPlaneUsingExtent); var result = planeHitTestResults.FirstOrDefault(); if (result != null) { var planeHitTestPosition = result.WorldTransform.Translation(); var planeAnchor = result.Anchor; return(planeHitTestPosition, (ARPlaneAnchor)planeAnchor, true); } // ------------------------------------------------------------------------------- // 2. Collect more information about the environment by hit testing against // the feature point cloud, but do not return the result yet. SCNVector3?featureHitTestPosition = null; var highQualityFeatureHitTestResult = false; var highQualityfeatureHitTestResults = sceneView.HitTestWithFeatures(position, 18, 0.2, 2.0); if (highQualityfeatureHitTestResults.Count() > 0) { var highQualityFeatureHit = highQualityfeatureHitTestResults.First(); featureHitTestPosition = highQualityFeatureHit.Position; highQualityFeatureHitTestResult = true; } // ------------------------------------------------------------------------------- // 3. If desired or necessary (no good feature hit test result): Hit test // against an infinite, horizontal plane (ignoring the real world). if ((infinitePlane && dragOnInfinitePlanesEnabled) || !highQualityFeatureHitTestResult) { if (objectPos.HasValue) { var pointOnInfinitePlane = sceneView.HitTestWithInfiniteHorizontalPlane(position, objectPos.Value); if (pointOnInfinitePlane != null) { return(pointOnInfinitePlane, null, true); } } } // ------------------------------------------------------------------------------- // 4. If available, return the result of the hit test against high quality // features if the hit tests against infinite planes were skipped or no // infinite plane was hit. if (highQualityFeatureHitTestResult) { return(featureHitTestPosition, null, false); } // ------------------------------------------------------------------------------- // 5. As a last resort, perform a second, unfiltered hit test against features. // If there are no features in the scene, the result returned here will be nil. var unfilteredFeatureHitTestResults = sceneView.HitTestWithFeatures(position); if (unfilteredFeatureHitTestResults.Count() > 0) { var unfilteredFeaturesResult = unfilteredFeatureHitTestResults.First(); return(unfilteredFeaturesResult.Position, null, false); } return(null, null, false); }
public static (SCNVector3?, ARPlaneAnchor, bool) WorldPositionFromScreenPosition(CGPoint position, ARSCNView sceneView, SCNVector3?objectPos, bool infinitePlane = false) { // ------------------------------------------------------------------------------- // 1. Always do a hit test against existing plane anchors first. // (If any such anchors exist & only within their extents.) var result = sceneView.HitTest(position, ARHitTestResultType.ExistingPlaneUsingExtent)?.FirstOrDefault(); if (result != null) { var planeHitTestPosition = result.WorldTransform.GetTranslation(); var planeAnchor = result.Anchor; // Return immediately - this is the best possible outcome. return(planeHitTestPosition, planeAnchor as ARPlaneAnchor, true); } // ------------------------------------------------------------------------------- // 2. Collect more information about the environment by hit testing against // the feature point cloud, but do not return the result yet. SCNVector3?featureHitTestPosition = null; var highQualityFeatureHitTestResult = false; var highQualityfeatureHitTestResults = sceneView.HitTestWithFeatures(position, 18f, 0.2f, 2f); if (highQualityfeatureHitTestResults.Any()) { featureHitTestPosition = highQualityfeatureHitTestResults[0].Position; highQualityFeatureHitTestResult = true; } // ------------------------------------------------------------------------------- // 3. If desired or necessary (no good feature hit test result): Hit test // against an infinite, horizontal plane (ignoring the real world). if (infinitePlane || !highQualityFeatureHitTestResult) { if (objectPos.HasValue) { var pointOnInfinitePlane = sceneView.HitTestWithInfiniteHorizontalPlane(position, objectPos.Value); if (pointOnInfinitePlane.HasValue) { return(pointOnInfinitePlane, null, true); } } } // ------------------------------------------------------------------------------- // 4. If available, return the result of the hit test against high quality // features if the hit tests against infinite planes were skipped or no // infinite plane was hit. if (highQualityFeatureHitTestResult) { return(featureHitTestPosition, null, false); } // ------------------------------------------------------------------------------- // 5. As a last resort, perform a second, unfiltered hit test against features. // If there are no features in the scene, the result returned here will be nil. var unfilteredFeatureHitTestResults = sceneView.HitTestWithFeatures(position); if (unfilteredFeatureHitTestResults.Any()) { var first = unfilteredFeatureHitTestResults[0]; return(first.Position, null, false); } return(null, null, false); }