private (SCNNode, float) FindAttachNodeNearPoint(SCNNode system, SCNNode node, SCNVector3 point, float tolerance) { var currentTolerance = tolerance; SCNNode currentClosestNode = null; // if this object has a socket node near ball node, then use it if (!string.IsNullOrEmpty(node.Name) && node.Name.StartsWith((ConstrainHierarchyComponent.SocketName), StringComparison.Ordinal)) { var attachOffset = node.ConvertPositionToNode(SCNVector3.Zero, system); var distance = (point - attachOffset).Length; if (distance < currentTolerance) { currentTolerance = distance; currentClosestNode = node; } } foreach (var child in node.ChildNodes) { var(socketNode, distance) = FindAttachNodeNearPoint(system, child, point, currentTolerance); if (socketNode != null) { currentTolerance = distance; currentClosestNode = socketNode; } } return(currentClosestNode, currentTolerance); }
public void CheckIfObjectShouldMoveOntoPlane(ARPlaneAnchor anchor, SCNNode planeAnchorNode) { foreach (var vo in VirtualObjects) { // Get the object's position in the plane's coordinate system. var objectPos = planeAnchorNode.ConvertPositionToNode(vo.Position, vo.ParentNode); if (Math.Abs(objectPos.Y) < float.Epsilon) { return; // The object is already on the plane - nothing to do here. } // Add 10% tolerance to the corners of the plane. var tolerance = 0.1f; var minX = anchor.Center.X - anchor.Extent.X / 2f - anchor.Extent.X * tolerance; var maxX = anchor.Center.X + anchor.Extent.X / 2f + anchor.Extent.X * tolerance; var minZ = anchor.Center.Z - anchor.Extent.Z / 2f - anchor.Extent.Z * tolerance; var maxZ = anchor.Center.Z + anchor.Extent.Z / 2f + anchor.Extent.Z * tolerance; if (objectPos.X < minX || objectPos.X > maxX || objectPos.Z < minZ || objectPos.Z > maxZ) { return; } // Drop the object onto the plane if it is near it. var verticalAllowance = 0.05f; var epsilon = 0.001; // Do not bother updating if the difference is less than a mm. var distanceToPlane = Math.Abs(objectPos.Y); if (distanceToPlane > epsilon && distanceToPlane < verticalAllowance) { Delegate.DidMoveObjectOntoNearbyPlane(this, vo); SCNTransaction.Begin(); SCNTransaction.AnimationDuration = distanceToPlane * 500; // Move 2mm per second SCNTransaction.AnimationTimingFunction = CAMediaTimingFunction.FromName(CAMediaTimingFunction.EaseInEaseOut); vo.Position = new SCNVector3(vo.Position.X, anchor.Transform.M32, vo.Position.Z); SCNTransaction.Commit(); } } }
private SCNNode SetupVehicle(SCNScene scene) { var carScene = SCNScene.FromFile("rc_car", ResourceManager.ResourceFolder, (NSDictionary)null); var chassisNode = carScene.RootNode.FindChildNode("rccarBody", false); chassisNode.Position = new SCNVector3(0f, 10f, 30f); chassisNode.Rotation = new SCNVector4(0f, 1f, 0f, (float)Math.PI); var body = SCNPhysicsBody.CreateDynamicBody(); body.AllowsResting = false; body.Mass = 80f; body.Restitution = 0.1f; body.Friction = 0.5f; body.RollingFriction = 0f; chassisNode.PhysicsBody = body; var frontCameraNode = SCNNode.Create(); frontCameraNode.Position = new SCNVector3(0f, 3.5f, 2.5f); frontCameraNode.Rotation = new SCNVector4(0f, 1f, 0f, (float)Math.PI); frontCameraNode.Camera = SCNCamera.Create(); frontCameraNode.Camera.XFov = 75f; frontCameraNode.Camera.ZFar = 500f; chassisNode.AddChildNode(frontCameraNode); scene.RootNode.AddChildNode(chassisNode); var pipeNode = chassisNode.FindChildNode("pipe", true); reactor = SCNParticleSystem.Create("reactor", ResourceManager.ResourceFolder); reactor.ParticleImage = ResourceManager.GetResourcePath("spark.png"); reactorDefaultBirthRate = reactor.BirthRate; reactor.BirthRate = 0; pipeNode.AddParticleSystem(reactor); SCNNode wheel0Node = chassisNode.FindChildNode("wheelLocator_FL", true); SCNNode wheel1Node = chassisNode.FindChildNode("wheelLocator_FR", true); SCNNode wheel2Node = chassisNode.FindChildNode("wheelLocator_RL", true); SCNNode wheel3Node = chassisNode.FindChildNode("wheelLocator_RR", true); var wheel0 = SCNPhysicsVehicleWheel.Create(wheel0Node); var wheel1 = SCNPhysicsVehicleWheel.Create(wheel1Node); var wheel2 = SCNPhysicsVehicleWheel.Create(wheel2Node); var wheel3 = SCNPhysicsVehicleWheel.Create(wheel3Node); var min = SCNVector3.Zero; var max = SCNVector3.Zero; wheel0Node.GetBoundingBox(ref min, ref max); float wheelHalfWidth = 0.5f * (max.X - min.X); wheel0.ConnectionPosition = SCNVector3.Add(wheel0Node.ConvertPositionToNode(SCNVector3.Zero, chassisNode), new SCNVector3(wheelHalfWidth, 0f, 0f)); wheel1.ConnectionPosition = SCNVector3.Subtract(wheel1Node.ConvertPositionToNode(SCNVector3.Zero, chassisNode), new SCNVector3(wheelHalfWidth, 0f, 0f)); wheel2.ConnectionPosition = SCNVector3.Add(wheel2Node.ConvertPositionToNode(SCNVector3.Zero, chassisNode), new SCNVector3(wheelHalfWidth, 0f, 0f)); wheel3.ConnectionPosition = SCNVector3.Subtract(wheel3Node.ConvertPositionToNode(SCNVector3.Zero, chassisNode), new SCNVector3(wheelHalfWidth, 0f, 0f)); var vehicle = SCNPhysicsVehicle.Create(chassisNode.PhysicsBody, new SCNPhysicsVehicleWheel[] { wheel0, wheel1, wheel2, wheel3 }); scene.PhysicsWorld.AddBehavior(vehicle); this.vehicle = vehicle; return(chassisNode); }