// End the game if the object has its initial orientation with a 10 degree tolerance. void EndGameOnCorrectOrientation() { if (!gameNodes.HasValue || !gameStarted) { return; } var gNodes = gameNodes.Value; var transform = gNodes.Object.Transform; var unitX = new SCNVector4(1, 0, 0, 0); var unitY = new SCNVector4(0, 1, 0, 0); var tX = SCNVector4.Transform(unitX, transform); var tY = SCNVector4.Transform(unitY, transform); float toleranceDegree = 10; var max_cos_angle = Math.Cos(toleranceDegree * Math.PI / 180); var cos_angleX = SCNVector4.Dot(unitX, tX); var cos_angleY = SCNVector4.Dot(unitY, tY); if (cos_angleX >= max_cos_angle && cos_angleY >= max_cos_angle) { EndGame(); } }
public static SCNMatrix4 ToSCNMatrix4(this NMatrix4 self) { var row0 = new SCNVector4(self.M11, self.M12, self.M13, self.M14); var row1 = new SCNVector4(self.M21, self.M22, self.M23, self.M24); var row2 = new SCNVector4(self.M31, self.M32, self.M33, self.M34); var row3 = new SCNVector4(self.M41, self.M42, self.M43, self.M44); return(new SCNMatrix4(row0, row1, row2, row3)); }
private void ApplyRandomTorque(SCNPhysicsBody physicsBody, float maxTorque) { var randomAxis = new SCNVector3((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble()); randomAxis = SCNVector3.Normalize(randomAxis); var randomTorque = new SCNVector4(randomAxis, (float)(random.NextDouble() * 2d - 1d) * maxTorque); physicsBody.ApplyTorque(randomTorque, true); }
public static SCNVector4 Lerp(SCNVector4 vectorStart, SCNVector4 vectorEnd, nfloat t) { var v = new SCNVector4( vectorStart.X + ((vectorEnd.X - vectorStart.X) * t), vectorStart.Y + ((vectorEnd.Y - vectorStart.Y) * t), vectorStart.Z + ((vectorEnd.Z - vectorStart.Z) * t), vectorStart.W + ((vectorEnd.W - vectorStart.W) * t) ); return(v); }
public static SCNVector4 Lerp (SCNVector4 vectorStart, SCNVector4 vectorEnd, nfloat t) { var v = new SCNVector4 ( vectorStart.X + ((vectorEnd.X - vectorStart.X) * t), vectorStart.Y + ((vectorEnd.Y - vectorStart.Y) * t), vectorStart.Z + ((vectorEnd.Z - vectorStart.Z) * t), vectorStart.W + ((vectorEnd.W - vectorStart.W) * t) ); return v; }
/// Matrix-Vector multiplication. Keep in mind that matrix types are named /// `FloatNxM` where `N` is the number of *columns* and `M` is the number of /// *rows*, so we multiply a `Float3x2 * Float3` to get a `Float2`, for /// example. internal static SCNVector4 Times(this SCNMatrix4 self, SCNVector4 vec) { Func <SCNVector4, float> elementSum = v => v.X + v.Y + v.Z + v.W; Func <SCNVector4, float, float> rowTimesVecEl = (row, s) => elementSum(SCNVector4.Multiply(row, s)); var x = rowTimesVecEl(self.Row0, vec.X); var y = rowTimesVecEl(self.Row1, vec.Y); var z = rowTimesVecEl(self.Row2, vec.Z); var w = rowTimesVecEl(self.Row3, vec.W); return(new SCNVector4(x, y, z, w)); }
void AssertEqual(SCNVector4 vector, string message, pfloat m1, pfloat m2, pfloat m3, pfloat m4) { if (m1 == vector.X && m2 == vector.Y && m3 == vector.Z && m4 == vector.W) { return; } var expectedString = vector.ToString(); var actualString = $"({m1}, {m2}, {m3}, {m4})"; Assert.Fail($"Expected vector:\n{expectedString}\nActual vector:\n{actualString}\n{message}"); }
internal static SCNVector3?UnprojectPointLocal(this ARSCNView self, CGPoint point, NMatrix4 planeTransform) { var result = self.Unproject(point, planeTransform); // Convert the result into the plane's local coordinate system. var pt = new SCNVector4(result.X, result.Y, result.Z, 1); var invertedPlane = planeTransform.ToSCNMatrix4(); invertedPlane.Invert(); var localResult = invertedPlane.Times(pt); return(localResult.Xyz); }
public void Vector() { var v = new SCNVector4(); var u = SCNVector4.UnitX; #if !XAMCORE_2_0 // that was possible in classic - but will now trigger a CS0198 SCNVector4.UnitX = v; #else u.X = 2; #endif Assert.That(SCNVector4.UnitX, Is.Not.EqualTo(u), "UnitX"); u = SCNVector4.UnitY; #if !XAMCORE_2_0 // that was possible in classic - but will now trigger a CS0198 SCNVector4.UnitY = v; #else u.Y = 2; #endif Assert.That(SCNVector4.UnitY, Is.Not.EqualTo(u), "UnitY"); u = SCNVector4.UnitZ; #if !XAMCORE_2_0 // that was possible in classic - but will now trigger a CS0198 SCNVector4.UnitZ = v; #else u.Z = 2; #endif Assert.That(SCNVector4.UnitZ, Is.Not.EqualTo(u), "UnitZ"); u = SCNVector4.UnitW; #if !XAMCORE_2_0 // that was possible in classic - but will now trigger a CS0198 SCNVector4.UnitW = v; #else u.W = 2; #endif Assert.That(SCNVector4.UnitW, Is.Not.EqualTo(u), "UnitW"); u = SCNVector4.Zero; #if !XAMCORE_2_0 // that was possible in classic - but will now trigger a CS0198 SCNVector4.Zero = v; Assert.That(SCNVector4.Zero, Is.EqualTo(u), "Zero"); #else u.W = 2; Assert.That(SCNVector4.Zero, Is.Not.EqualTo(u), "Zero"); #endif }
public static SCNMatrix4 Normalize(this SCNMatrix4 matrix) { // for row-major matrixes only var normalized = matrix; var row0 = SCNVector4.Normalize(matrix.Row0); var row1 = SCNVector4.Normalize(matrix.Row1); var row2 = SCNVector4.Normalize(matrix.Row2); normalized.Row0 = row0; normalized.Row1 = row1; normalized.Row2 = row2; return(normalized); }
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; } } }
public static SCNMatrix4 Interpolate(SCNMatrix4 scnm0, SCNMatrix4 scnmf, nfloat factor) { SCNVector4 p0 = scnm0.Row3; SCNVector4 pf = scnmf.Row3; var q0 = scnm0.ToQuaternion(); var qf = scnmf.ToQuaternion(); SCNVector4 pTmp = Lerp(p0, pf, factor); SCNQuaternion qTmp = SCNQuaternion.Slerp(q0, qf, (float)factor); SCNMatrix4 rTmp = qTmp.ToMatrix4(); SCNMatrix4 transform = new SCNMatrix4( rTmp.M11, rTmp.M12, rTmp.M13, 0.0f, rTmp.M21, rTmp.M22, rTmp.M23, 0.0f, rTmp.M31, rTmp.M32, rTmp.M33, 0.0f, pTmp.X, pTmp.Y, pTmp.Z, 1.0f ); return(transform); }
private void UpdateTransform(SCNVector3 position, ARCamera camera) { // Add to list of recently visited positions RecentFocusSquarePositions[recentFocusSquarePositionIndex] = position; // Increment current position, rolling over to beginning recentFocusSquarePositionIndex = ++recentFocusSquarePositionIndex % RecentFocusSquarePositions.Length; // Note that we don't really care about "current position" as we just average all the positions // Move to average of recent positions to avoid jitter var average = Utilities.AverageVector3List(RecentFocusSquarePositions); Position = average; this.SetUniformScale(ScaleBasedOnDistance(camera)); // Correct y rotation of camera square if (camera != null) { var tilt = (float)Math.Abs(camera.EulerAngles.X); var threshold1 = (float)(Math.PI / 2f * 0.65f); var threshold2 = (float)(Math.PI / 2f * 0.75f); var yaw = (float)Math.Atan2(camera.Transform.M11, camera.Transform.M12); var angle = 0f; if (tilt >= 0 && tilt < threshold1) { angle = camera.EulerAngles.Y; } else if (threshold1 < threshold2) { var relativeInRange = Math.Abs((tilt - threshold1) / (threshold2 / threshold1)); var normalizedY = Normalize(camera.EulerAngles.Y, yaw); angle = normalizedY * (1 - relativeInRange) + yaw * relativeInRange; } else { angle = yaw; } Rotation = new SCNVector4(0, 1, 0, angle); } }
unsafe void UpdatePose() { float[] mPoseBuffer = new float[16]; int mTrackingState = 0; fixed(float *ptr = &mPoseBuffer[0]) { // R T // 0 1 int bufferSize = 16; mTrackingState = SDPlugin.SixDegreesSDK_GetPose(ptr, bufferSize); } switch (mTrackingState) { case (int)SDPlugin.SDTrackingQuality.Good: case (int)SDPlugin.SDTrackingQuality.Limited: { if (mTrackingState > 0) { // Update camera pose var row0 = new SCNVector4(mPoseBuffer[0], mPoseBuffer[1], mPoseBuffer[2], mPoseBuffer[3]); var row1 = new SCNVector4(mPoseBuffer[4], mPoseBuffer[5], mPoseBuffer[6], mPoseBuffer[7]); var row2 = new SCNVector4(mPoseBuffer[8], mPoseBuffer[9], mPoseBuffer[10], mPoseBuffer[11]); var row3 = new SCNVector4(mPoseBuffer[12], mPoseBuffer[13], mPoseBuffer[14], mPoseBuffer[15]); SCNMatrix4 poseMatrix = new SCNMatrix4(row0, row1, row2, row3); } break; } case (int)SDPlugin.SDTrackingQuality.None: default: { break; } } }
public static SCNVector4 Multiply(this SCNMatrix4 matrix, SCNVector4 vector) { var x = matrix.Column0.X * vector.X; var y = matrix.Column0.Y * vector.X; var z = matrix.Column0.Z * vector.X; var w = matrix.Column0.W * vector.X; x += matrix.Column1.X * vector.Y; y += matrix.Column1.Y * vector.Y; z += matrix.Column1.Z * vector.Y; w += matrix.Column1.W * vector.Y; x += matrix.Column2.X * vector.Z; y += matrix.Column2.Y * vector.Z; z += matrix.Column2.Z * vector.Z; w += matrix.Column2.W * vector.Z; x += matrix.Column3.X * vector.W; y += matrix.Column3.Y * vector.W; z += matrix.Column3.Z * vector.W; w += matrix.Column3.W * vector.W; return(new SCNVector4(x, y, z, w)); }
public void Vector() { var v = new SCNVector4(); var u = SCNVector4.UnitX; u.X = 2; Assert.That(SCNVector4.UnitX, Is.Not.EqualTo(u), "UnitX"); u = SCNVector4.UnitY; u.Y = 2; Assert.That(SCNVector4.UnitY, Is.Not.EqualTo(u), "UnitY"); u = SCNVector4.UnitZ; u.Z = 2; Assert.That(SCNVector4.UnitZ, Is.Not.EqualTo(u), "UnitZ"); u = SCNVector4.UnitW; u.W = 2; Assert.That(SCNVector4.UnitW, Is.Not.EqualTo(u), "UnitW"); u = SCNVector4.Zero; u.W = 2; Assert.That(SCNVector4.Zero, Is.Not.EqualTo(u), "Zero"); }
// End the game if the object has its initial orientation with a 10 degree tolerance. void EndGameOnCorrectOrientation () { if (!gameNodes.HasValue || !gameStarted) return; var gNodes = gameNodes.Value; var transform = gNodes.Object.Transform; var unitX = new SCNVector4 (1, 0, 0, 0); var unitY = new SCNVector4 (0, 1, 0, 0); var tX = SCNVector4.Transform (unitX, transform); var tY = SCNVector4.Transform (unitY, transform); float toleranceDegree = 10; var max_cos_angle = Math.Cos (toleranceDegree * Math.PI / 180); var cos_angleX = SCNVector4.Dot (unitX, tX); var cos_angleY = SCNVector4.Dot (unitY, tY); if (cos_angleX >= max_cos_angle && cos_angleY >= max_cos_angle) EndGame (); }
public static bool AlmostEqual(this SCNVector4 self, SCNVector4 value, float tolerance) { return((self - value).Length <= tolerance); }
public static bool HasNaN(this SCNVector4 self) { return(float.IsNaN(self.X) || float.IsNaN(self.Y) || float.IsNaN(self.Z) || float.IsNaN(self.W)); }
private SCNVector3 ComputeBallPosition(CameraInfo cameraInfo) { var cameraRay = cameraInfo.Ray; // These should be based on the projectile radius. // This affects centering of ball, and can hit near plane of camera // This is always centering to one edge of screen independent of screen orient // We always want the ball at the bottom of the screen. var distancePullToCamera = 0.21f; var ballShiftDown = 0.2f; var targetBallPosition = cameraRay.Position + cameraRay.Direction * distancePullToCamera; var cameraDown = -SCNVector4.Normalize(cameraInfo.Transform.Column1).Xyz; targetBallPosition += cameraDown * ballShiftDown; // Clamp to only the valid side var pullWorldPosition = this.pullOrigin.WorldPosition; if (pullWorldPosition.Z < 0f) { targetBallPosition.Z = Math.Min(targetBallPosition.Z, pullWorldPosition.Z); } else { targetBallPosition.Z = Math.Max(targetBallPosition.Z, pullWorldPosition.Z); } // Clamp to cone/circular core var yDistanceFromPull = Math.Max(0f, pullWorldPosition.Y - targetBallPosition.Y); var minBallDistanceFromPull = 0.5f; var pullBlockConeSlope = 1.0f; var pullBlockConeRadius = yDistanceFromPull / pullBlockConeSlope; var pullBlockCoreRadius = Math.Max(minBallDistanceFromPull, pullBlockConeRadius); // if pull is in the core, move it out. var pullWorldPositionGrounded = new SCNVector3(pullWorldPosition.X, 0f, pullWorldPosition.Z); var targetPullPositionGrounded = new SCNVector3(targetBallPosition.X, 0f, targetBallPosition.Z); var targetInitialToTargetPull = targetPullPositionGrounded - pullWorldPositionGrounded; if (pullBlockCoreRadius > targetInitialToTargetPull.Length) { var moveOutDirection = SCNVector3.Normalize(targetInitialToTargetPull); var newTargetPullPositionGrounded = pullWorldPositionGrounded + moveOutDirection * pullBlockCoreRadius; targetBallPosition = new SCNVector3(newTargetPullPositionGrounded.X, targetBallPosition.Y, newTargetPullPositionGrounded.Z); } // only use the 2d distance, so that user can gauage stretch indepdent of mtch var distance2D = targetBallPosition - pullWorldPosition; var stretchY = Math.Abs(distance2D.Y); distance2D.Y = 0f; var stretchDistance = distance2D.Length; this.stretch = DigitExtensions.Clamp((double)stretchDistance, this.properties.MinStretch, this.properties.MaxStretch); // clamp a little bit farther than maxStretch // can't let the strap move back too far right now var clampedStretchDistance = (float)(1.1d * this.properties.MaxStretch); if (stretchDistance > clampedStretchDistance) { targetBallPosition = (clampedStretchDistance / stretchDistance) * (targetBallPosition - pullWorldPosition) + pullWorldPosition; stretchDistance = clampedStretchDistance; } // Make this optional, not required. You're often at max stretch. // Also have a timer for auto-launch. This makes it very difficuilt to test // storing state in member data this.IsPulledTooFar = stretchDistance > (float)(this.properties.MaxStretch) || stretchY > (float)(this.properties.MaxStretch); return(targetBallPosition); }
public static void SetFloat4(this SCNGeometry geometry, string uniform, SCNVector4 value) { geometry.SetValueForKey(NSValue.FromVector(value), new NSString(uniform)); }
public void Draw(MTKView view) { if (!SDPlugin.IsSDKReady) { return; } // Update sizes if (backgroundTextureSize.Width == 0 && backgroundTextureSize.Height == 0) { var size = MakeBackgroundTextureSize(); backgroundTextureSize = size; UpdateMTKViewFrame(); } // Draw meshes if (SDPlugin.ShowMesh) { MeshController.Update(); } // Get pose and tracking quality var localOrientation = UIApplication.SharedApplication.StatusBarOrientation; float[] mPoseBuffer = new float[16]; int trackingQuality = 0; unsafe { fixed(float *ptr = &mPoseBuffer[0]) { // R T // 0 1 int bufferSize = 16; trackingQuality = SDPlugin.SixDegreesSDK_GetPose(ptr, bufferSize); } } if (trackingQuality > 0) { // Update camera pose var row0 = new SCNVector4(mPoseBuffer[0], mPoseBuffer[1], mPoseBuffer[2], mPoseBuffer[3]); var row1 = new SCNVector4(mPoseBuffer[4], mPoseBuffer[5], mPoseBuffer[6], mPoseBuffer[7]); var row2 = new SCNVector4(mPoseBuffer[8], mPoseBuffer[9], mPoseBuffer[10], mPoseBuffer[11]); var row3 = new SCNVector4(mPoseBuffer[12], mPoseBuffer[13], mPoseBuffer[14], mPoseBuffer[15]); SCNMatrix4 poseMatrix = new SCNMatrix4(row0, row1, row2, row3); CameraNode.WorldTransform = poseMatrix; // Update camera projection var projectionTransform = MakeProjectionMatrix(localOrientation); CameraNode.Camera.ProjectionTransform = projectionTransform; } // Update vertex factory if (vertexFactory.IsComplete == false || orientation != localOrientation) { vertexFactory.Update(localOrientation, backgroundTextureSize); } orientation = localOrientation; // Draw background texture var texturePtr = SDPlugin.SixDegreesSDK_GetBackgroundTexture(); if (texturePtr != IntPtr.Zero) { var obj = ObjCRuntime.Runtime.GetINativeObject <IMTLTexture>(texturePtr, false); Draw((IMTLTexture)obj); } if (commandQueue != null) { var commandBuffer = commandQueue.CommandBuffer(); var currentDrawable = mtkView.CurrentDrawable; double CurrentTime = CAAnimation.CurrentMediaTime(); var screenScale = UIScreen.MainScreen.Scale; var viewport = new CGRect(x: 0, y: 0, width: mtkView.Frame.Width * screenScale, height: mtkView.Frame.Height * screenScale); var renderPassDescriptor = MTLRenderPassDescriptor.CreateRenderPassDescriptor(); renderPassDescriptor.ColorAttachments[0].Texture = currentDrawable.Texture; renderPassDescriptor.ColorAttachments[0].LoadAction = MTLLoadAction.Load; renderPassDescriptor.ColorAttachments[0].StoreAction = MTLStoreAction.Store; renderer.Render(CurrentTime, viewport, commandBuffer, renderPassDescriptor); commandBuffer.PresentDrawable(currentDrawable); commandBuffer.Commit(); } }