Exemplo n.º 1
0
        internal SCNPhysicsShapeOptions(NSDictionary source)
        {
            var ret = source [SCNPhysicsShapeOptionsKeys.Type] as NSString;

            if (ret != null)
            {
                if (ret == SCNPhysicsShapeOptionsTypes.BoundingBox)
                {
                    ShapeType = SCNPhysicsShapeType.BoundingBox;
                }
                else if (ret == SCNPhysicsShapeOptionsTypes.ConcavePolyhedron)
                {
                    ShapeType = SCNPhysicsShapeType.ConcavePolyhedron;
                }
                else if (ret == SCNPhysicsShapeOptionsTypes.ConvexHull)
                {
                    ShapeType = SCNPhysicsShapeType.ConvexHull;
                }
            }
            var bret = source [SCNPhysicsShapeOptionsKeys.KeepAsCompound] as NSNumber;

            if (bret != null)
            {
                KeepAsCompound = bret.Int32Value != 0;
            }
            var nret = source [SCNPhysicsShapeOptionsKeys.Scale] as NSValue;

            if (nret != null)
            {
                Scale = nret.Vector3Value;
            }
        }
Exemplo n.º 2
0
 public static SCNPhysicsShape Create(SCNNode node,
                                      SCNPhysicsShapeType?shapeType = null,
                                      bool?keepAsCompound           = null,
                                      SCNVector3?scale = null)
 {
     return(Create(node, new SCNPhysicsShapeOptions {
         ShapeType = shapeType,
         KeepAsCompound = keepAsCompound,
         Scale = scale
     }.ToDictionary()));
 }
Exemplo n.º 3
0
        public static SCNVector3?GetAverage(this IList <SCNVector3> vectors)
        {
            SCNVector3?result = null;

            if (vectors != null && vectors.Count > 0)
            {
                var sum = vectors.Aggregate(SCNVector3.Zero, (vector1, vector2) => vector1 + vector2);
                result = sum / vectors.Count;
            }

            return(result);
        }
Exemplo n.º 4
0
        public void InitRotateEntityField(SCNScene scene, SCNVector3 coord1, SCNVector3 coord2)
        {
            entityPositionOnDoubleTouch         = _entityNode.Position;
            entityEulerAnglesOnDoubleTouch      = _entityNode.EulerAngles;
            entityFieldEulerAnglesOnDoubleTouch = _fieldNode.EulerAngles;

            doubleTouchInitPosition = (coord1 + coord2) / 2;
            var diff     = coord2 - coord1;
            var len      = diff.Length;
            var zcomp    = diff.Z;
            var dirAngle = (float)Math.Acos(zcomp / len);

            doubleTouchInitEulerAnglesY = (diff.X > 0) ? dirAngle : (2 * (float)Math.PI - dirAngle);
        }
Exemplo n.º 5
0
        private void UpdateCatapultStable()
        {
            if (!this.Disabled)
            {
                // Catapult will be unstable when the physics settles, therefore we do not update catapult's stability status
                if (GameTime.TimeSinceLevelStart > CatapultPhysicsSettleTime)
                {
                    // Cannot use simdVelocity on client since simdVelocity could be high from physicsSync interacting with local physics engine
                    if (!this.lastPosition.HasValue)
                    {
                        this.lastPosition = this.Base.PresentationNode.WorldPosition;
                        return;
                    }

                    var position = this.Base.PresentationNode.WorldPosition;
                    var speed    = ((position - this.lastPosition.Value) / (float)GameTime.DeltaTime).Length;
                    this.lastPosition = position;

                    // Base below table?
                    // Base tilted? base's up vector must maintain some amount of y to be determined as stable
                    var transform = this.Base.PresentationNode.Transform;
                    transform.Transpose();
                    var baseUp = SCNVector4.Normalize(transform.Column1);
                    if (position.Y < -1f || Math.Abs(baseUp.Y) < MinStableTiltBaseUpY)
                    {
                        // Switch to knocked mode
                        if (!this.isCatapultKnocked)
                        {
                            this.catapultKnockedStartTime = GameTime.Time;
                        }

                        this.isCatapultKnocked = true;
                        this.isCatapultStable  = false;
                        return;
                    }

                    this.isCatapultKnocked = false;

                    // Base could be moving although the catapult is not knocked
                    this.isCatapultStable = speed < MaxSpeedToCountAsStable;
                }
            }
        }
Exemplo n.º 6
0
        public static SCNVector3?HitTestWithInfiniteHorizontalPlane(this ARSCNView view, CGPoint point, SCNVector3 pointOnPlane)
        {
            SCNVector3?result = null;

            var ray = view.HitTestRayFromScreenPosition(point);

            if (ray.HasValue)
            {
                // Do not intersect with planes above the camera or if the ray is almost parallel to the plane.
                if (ray.Value.Direction.Y <= -0.03f)
                {
                    // Return the intersection of a ray from the camera through the screen position with a horizontal plane
                    // at height (Y axis).
                    result = Utilities.RayIntersectionWithHorizontalPlane(ray.Value.Origin, ray.Value.Direction, pointOnPlane.Y);
                }
            }

            return(result);
        }
        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);
        }
Exemplo n.º 8
0
        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);
        }
Exemplo n.º 9
0
        private static SCNVector3?HitTestPointCloud(CGPoint point, ARSCNView sceneView, double coneOpeningAngleInDegrees, double minDistance = 0, double maxDistance = Double.MaxValue)
        {
            //var results = new List<FeatureHitTestResult>();
            var minHitTestResultDistance = float.MaxValue;
            //FeatureHitTestResult closestFeauture = null;
            SCNVector3?closestFeauturePosition = null;

            if (sceneView.Session == null || ARGamePlay.CurrentFrame == null)
            {
                return(null); //results.ToArray();
            }
            var features = ARGamePlay.CurrentFrame.RawFeaturePoints;

            if (features == null)
            {
                return(null); //results.ToArray();
            }

            var ray = sceneView.HitTestRayFromScreenPos(point);

            if (ray == null)
            {
                return(null); //results.ToArray();
            }

            var maxAngleInDeg = Math.Min(coneOpeningAngleInDegrees, 360) / 2.0;
            var maxAngle      = (maxAngleInDeg / 180) * Math.PI;

            foreach (var featurePos in features.Points)
            {
                var scnFeaturePos   = new SCNVector3(featurePos.X, featurePos.Y, featurePos.Z);
                var originToFeature = scnFeaturePos - ray.Origin;
                //var crossProduct = originToFeature.Cross(ray.Direction);
                //var featureDistanceFromResult = crossProduct.LengthFast;

                var hitTestResult         = ray.Origin + (ray.Direction * (ray.Direction.Dot(originToFeature)));
                var hitTestResultDistance = (hitTestResult - ray.Origin).LengthFast;

                if (hitTestResultDistance < minDistance || hitTestResultDistance > maxDistance)
                {
                    // Skip this feature -- it's too close or too far
                    continue;
                }

                var originToFeatureNormalized = originToFeature.Normalized();
                var angleBetweenRayAndFeature = Math.Acos(ray.Direction.Dot(originToFeatureNormalized));

                if (angleBetweenRayAndFeature > maxAngle)
                {
                    // Skip this feature -- it's outside the cone
                    continue;
                }

                if (hitTestResultDistance < minHitTestResultDistance)
                {
                    minHitTestResultDistance = hitTestResultDistance;
                    closestFeauturePosition  = hitTestResult; //new FeatureHitTestResult(hitTestResult); //, hitTestResultDistance, scnFeaturePos, featureDistanceFromResult);
                }

                // All tests passed: Add the hit against this feature to the results.
                //results.Add(new FeatureHitTestResult(hitTestResult, hitTestResultDistance, scnFeaturePos, featureDistanceFromResult));
            }

            return(closestFeauturePosition);

            //         if(closestFeauture != null)
            //         {
            //             results.Add(closestFeauture);
            //         }

            ////// Sort the results by feature distance to the ray.
            ////results.Sort((a, b) => a.DistanceToRayOrigin.CompareTo(b.DistanceToRayOrigin));

            ////// Cap the list to maxResults.
            ////results.GetRange(0, Math.Min(results.Count(), maxResults));
            //return results.ToArray();
        }
Exemplo n.º 10
0
        public static (SCNVector3?hitPoint, HitType hitType) FindNearestWorldPointToScreenPoint(CGPoint point, ARSCNView sceneView, SCNVector3?pointOnPlane)
        {
            var planeHitPosition = HitTestExistingPlanes(point, sceneView);

            if (planeHitPosition.HasValue)
            {
                return(planeHitPosition, HitType.Plane);
            }

            var pointCloudHitPosition = HitTestPointCloud(point, sceneView, 18, 0.2, 2.0);

            if (pointCloudHitPosition.HasValue)
            {
                return(pointCloudHitPosition, HitType.FeaturePoint);
            }

            //if(pointOnPlane.HasValue)
            //{
            //    var infinitePlaneHitPosition = HitTestWithInfiniteHorizontalPlane(point, sceneView, pointOnPlane.Value);
            //    if (infinitePlaneHitPosition.HasValue)
            //        return infinitePlaneHitPosition.Value;
            //}

            return(null, HitType.None);
        }