public SimulatedTransform(SCNVector3 position, SCNQuaternion orientation, SCNVector3 velocity, bool dynamic) { this.Position = position; this.Orientation = orientation; this.Velocity = velocity; this.Dynamic = dynamic; }
public static SCNMatrix4 ToMatrix4(this SCNQuaternion quaternion) { quaternion.Normalize(); nfloat x = quaternion.X; nfloat y = quaternion.Y; nfloat z = quaternion.Z; nfloat w = quaternion.W; nfloat doubleX = x + x; nfloat doubleY = y + y; nfloat doubleZ = z + z; nfloat doubleW = w + w; return(new SCNMatrix4( 1.0f - doubleY * y - doubleZ * z, doubleX * y + doubleW * z, doubleX * z - doubleW * y, 0.0f, doubleX * y - doubleW * z, 1.0f - doubleX * x - doubleZ * z, doubleY * z + doubleW * x, 0.0f, doubleX * z + doubleW * y, doubleY * z - doubleW * x, 1.0f - doubleX * x - doubleY * y, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f )); }
/// <summary> /// Inch geometry back to original offset from rigid body /// </summary> private void UpdateSmooth(double deltaTime) { // allow some motion up to a maximum offset var posDelta = this.parentOffPos - this.sourceOffPos; if (posDelta.Length > MaxCorrection) { posDelta = MaxCorrection * SCNVector3.Normalize(posDelta); } // lerp pos var newPos = this.sourceOffPos + posDelta; this.geometryNode.Position = newPos; // cap the max rotation that can show through var quatDelta = this.parentOffRot.Divide(this.sourceOffRot); quatDelta.ToAxisAngle(out SCNVector3 _, out float angle); if (angle > MaxRotation) { this.geometryNode.Orientation = SCNQuaternion.Slerp(this.sourceOffRot, this.parentOffRot, MaxRotation / angle); } else { this.geometryNode.Orientation = this.parentOffRot; } }
public void Apply(PhysicsNodeData nodeData, bool isHalfway) { if (this.PhysicsNode != null) { // if we're not alive, avoid applying physics updates. // this will allow objects on clients to get culled properly if (this.IsAlive) { if (isHalfway) { this.PhysicsNode.WorldPosition = (nodeData.Position + this.PhysicsNode.WorldPosition) * 0.5f; this.PhysicsNode.Orientation = SCNQuaternion.Slerp(this.PhysicsNode.Orientation, nodeData.Orientation, 0.5f); } else { this.PhysicsNode.WorldPosition = nodeData.Position; this.PhysicsNode.Orientation = nodeData.Orientation; } if (this.PhysicsNode.PhysicsBody != null) { this.PhysicsNode.PhysicsBody.ResetTransform(); this.PhysicsNode.PhysicsBody.Velocity = nodeData.Velocity; this.PhysicsNode.PhysicsBody.AngularVelocity = nodeData.AngularVelocity; } } } }
public override void Update(double deltaTimeInSeconds) { this.currentTime += deltaTimeInSeconds; this.CalcCurrentFrameIndex(); var alpha = (float)((this.currentTime - this.wayPoints[currentFrame].Time) / (this.wayPoints[currentFrame + 1].Time - this.wayPoints[currentFrame].Time)); alpha = DigitExtensions.Clamp(alpha, 0f, 1f); var curPos = this.wayPoints[currentFrame].Pos; var curTan = this.wayPoints[currentFrame].Tangent; var curRot = this.wayPoints[currentFrame].Rot; var nextPos = this.wayPoints[currentFrame + 1].Pos; var nextTan = this.wayPoints[currentFrame + 1].Tangent; var nextRot = this.wayPoints[currentFrame + 1].Rot; var newPosX = this.HermiteCurve(curPos.X, nextPos.X, curTan.X, nextTan.X, alpha); var newPosY = this.HermiteCurve(curPos.Y, nextPos.Y, curTan.Y, nextTan.Y, alpha); var newPosZ = this.HermiteCurve(curPos.Z, nextPos.Z, curTan.Z, nextTan.Z, alpha); var newQuat = SCNQuaternion.Slerp(curRot, nextRot, alpha); node.WorldPosition = new SCNVector3(newPosX, newPosY, newPosZ); node.WorldOrientation = newQuat; // update child rigid bodies to percolate into physics if (this.Entity is GameObject entity) { if (entity.PhysicsNode?.PhysicsBody != null) { entity.PhysicsNode.PhysicsBody.ResetTransform(); } } }
// we can make this call when the physics changes to smooth it // make sure its called BEFORE the physics value is changed in the rigid body // it works by separating the actual geometry slightly from the physics to correct for the visual pop when position is changed private void CorrectPhysics(SCNNode node, SCNVector3 pos, SCNQuaternion rot) { // find old value var oldTransform = this.geometryNode.WorldTransform; // change position of object node.Position = pos; node.Orientation = rot; this.physicsNode.PhysicsBody.ResetTransform(); // restore offset if (node != this.geometryNode) { this.geometryNode.WorldTransform = oldTransform; this.sourceOffPos = this.geometryNode.Position; this.sourceOffRot = geometryNode.Orientation; } else { this.sourceOffPos = parentOffPos; this.sourceOffRot = parentOffRot; } // cap the maximum deltas we allow in rotation and position space this.UpdateSmooth(1d / 60d); }
public Waypoint(SCNVector3 pos, SCNVector3 tangent, SCNQuaternion rot, double time) { this.Pos = pos; this.Tangent = tangent; this.Rot = rot; this.Time = time; }
public override void RotateWithEvent(NSEvent theEvent) { base.RotateWithEvent(theEvent); var r = SCNQuaternion.FromAxisAngle(new SCNVector3(0, 0, 1), -theEvent.Rotation / 180); r.Normalize(); Trackball.Rotate(r); }
public GamePhysicsSmoothComponent(SCNNode physicsNode, SCNNode geometryNode) : base() { this.physicsNode = physicsNode; this.geometryNode = geometryNode; // get initial offset this.parentOffPos = this.geometryNode.Position; this.parentOffRot = this.geometryNode.Orientation; }
public static SCNQuaternion CreateQuaternion(SCNVector3 v1, SCNVector3 v2) { var a = SCNVector3.Cross(v1, v2); var w = (float)Math.Sqrt(v1.LengthSquared * v2.LengthSquared) + SCNVector3.Dot(v1, v2); var result = new SCNQuaternion(a.X, a.Y, a.Z, w); result.Normalize(); return(result); }
/// <summary> /// Computes the tangent position of the rope based on a given fixture /// </summary> private SCNVector3 TangentPosition(SCNVector3 fixture) { var r = this.ballRadius; var d = fixture - this.ballPosition; var alpha = (float)Math.Acos(r / d.Length); d = this.ballRadius * SCNVector3.Normalize(d); var rot = SCNQuaternion.FromAxisAngle(this.UpVector, fixture == this.FixturePositionL ? -alpha : alpha); var d_rotated = rot.Act(d); return(d_rotated + this.ballPosition); }
public SlingShotSimulation(SCNNode rootNode, int count, float segmentRadius) : base() { this.InitializeHelpers(); for (var i = 0; i < count; i++) { var isStatic = (i < this.BoneInset) || (i >= count - this.BoneInset); var quaternion = SCNQuaternion.FromAxisAngle(SCNVector3.UnitX, 0); var transform = new SimulatedTransform(SCNVector3.Zero, quaternion, SCNVector3.Zero, !isStatic); this.simulatedTransforms.Add(transform); } }
public void Quaternion() { var id = SCNQuaternion.Identity; #if !XAMCORE_2_0 var q = new SCNQuaternion(); // that was possible in classic - but will now trigger a CS0198 SCNQuaternion.Identity = q; #else id.W = 2; #endif Assert.That(SCNQuaternion.Identity, Is.Not.EqualTo(id), "Identity"); }
public static SCNVector3 Act(this SCNQuaternion self, SCNVector3 vector) { // Calculate the resulting vector using the Hamilton product // P' = RPR' // P = [0, p1, p2, p2] < -- vector // R = [w, x, y, z] < -- rotation // R' = [w, -x, -y, -z] var p = new SCNQuaternion(vector, 0f); var r = self; var rt = r; rt.Conjugate(); return(SCNQuaternion.Multiply(SCNQuaternion.Multiply(r, p), rt).Xyz); }
private void Setup(NVector3 extent) { // Translate and rotate line nodes to the correct transform var halfX = extent.X / 2; var halfY = extent.Y / 2; var halfZ = extent.Z / 2; // Two helper functions to isolate the allocations and casts Action <SCNNode, float, float, float> xlat = (node, extentX, extentY, extentZ) => node.LocalTranslate(new SCNVector3(extentX, extentY, extentZ)); Action <SCNNode, float, float, float, Axis> xlatAndRot = (node, extentX, extentY, extentZ, axis) => { xlat(node, extentX, extentY, extentZ); node.LocalRotate(SCNQuaternion.FromAxisAngle(axis.Normal().ToSCNVector3(), (float)-Math.PI / 2)); }; var halfWidth = extent.X / 2; var halfHeight = extent.Y / 2; var halfDepth = extent.Z / 2; xlatAndRot(lineNodes[0], 0, -halfHeight, -halfDepth, Axis.Z); xlatAndRot(lineNodes[1], -halfWidth, -halfHeight, 0, Axis.X); xlatAndRot(lineNodes[2], 0, -halfHeight, halfDepth, Axis.Z); xlatAndRot(lineNodes[3], halfWidth, -halfHeight, 0, Axis.X); xlat(lineNodes[4], -extent.X, 0, -halfDepth); xlat(lineNodes[5], -halfWidth, 0, halfDepth); xlat(lineNodes[6], halfWidth, 0, -halfDepth); xlat(lineNodes[7], halfWidth, 0, halfDepth); xlatAndRot(lineNodes[8], 0, halfHeight, -halfDepth, Axis.Z); xlatAndRot(lineNodes[9], -halfWidth, halfHeight, 0, Axis.X); xlatAndRot(lineNodes[10], 0, halfHeight, halfDepth, Axis.Z); xlatAndRot(lineNodes[11], halfWidth, halfHeight, 0, Axis.X); // Assign geometries lineNodes[0].Geometry = Cylinder(extent.X); lineNodes[1].Geometry = Cylinder(extent.Z); lineNodes[2].Geometry = Cylinder(extent.X); lineNodes[3].Geometry = Cylinder(extent.Z); lineNodes[4].Geometry = Cylinder(extent.Y); lineNodes[5].Geometry = Cylinder(extent.Y); lineNodes[6].Geometry = Cylinder(extent.Y); lineNodes[7].Geometry = Cylinder(extent.Y); lineNodes[8].Geometry = Cylinder(extent.X); lineNodes[9].Geometry = Cylinder(extent.Z); lineNodes[10].Geometry = Cylinder(extent.X); lineNodes[11].Geometry = Cylinder(extent.Z); }
SCNVector4 GetDirectionFromPosition(SCNVector3 currentPosition) { SCNVector3 target = LocationAlongPath(TimeAlongPath - 0.05f); SCNMatrix4 lookAt = SCNMatrix4.LookAt(currentPosition, target, new SCNVector3(0f, 1f, 0f)); SCNQuaternion q = lookAt.ToQuaternion(); nfloat angle = 0; q.ToAxisAngle(out target, out angle); if (PlayerCharacter.PlayerWalkDirection == WalkDirection.Left) { angle -= (nfloat)Math.PI; } return(new SCNVector4(0f, 1f, 0f, angle)); }
public static void SetTransform(this GKAgent2D agent, SCNMatrix4 newTransform) { var quatf = new SCNQuaternion(newTransform.Column3.Xyz, newTransform.Column3.W); SCNVector3 axis; #if !__OSX__ float angle; quatf.ToAxisAngle(out axis, out angle); agent.Rotation = -(angle + ((float)Math.PI / 2f)); agent.Position = new Vector2(newTransform.M41, newTransform.M43); #else nfloat angle; quatf.ToAxisAngle(out axis, out angle); agent.Rotation = -((float)angle + ((float)Math.PI / 2f)); agent.Position = new Vector2((float)newTransform.M41, (float)newTransform.M43); #endif }
public void CreateFlagSimulationFromNode(SCNNode node) { var meshData = new ClothSimMetalNode(this.device, Width, Height); var clothNode = SCNNode.FromGeometry(meshData.Geometry); var flag = node.FindChildNode("flagStaticWave", true); if (flag != null) { var boundingBoxMax = SCNVector3.Zero; var boundingBoxMin = SCNVector3.Zero; flag.GetBoundingBox(ref boundingBoxMin, ref boundingBoxMax); var existingFlagBV = boundingBoxMax - boundingBoxMin; var rescaleToMatchSizeMatrix = SCNMatrix4.Scale(existingFlagBV.X / (float)Width); var rotation = SCNQuaternion.FromAxisAngle(SCNVector3.UnitX, (float)Math.PI / 2f); var localTransform = rescaleToMatchSizeMatrix * SCNMatrix4.Rotate(rotation.ToQuaternion()); localTransform.Transpose(); var currentTransform = SCNMatrix4.Transpose(flag.Transform); var newTransform = currentTransform * localTransform; clothNode.Transform = SCNMatrix4.Transpose(newTransform);// flag.Transform * localTransform; if (clothNode.Geometry != null) { clothNode.Geometry.FirstMaterial = flag.Geometry?.FirstMaterial; if (clothNode.Geometry.FirstMaterial != null) { clothNode.Geometry.FirstMaterial.DoubleSided = true; } } flag.ParentNode.ReplaceChildNode(flag, clothNode); clothNode.Geometry.SetupPaintColorMask("flag_flagA"); clothNode.SetPaintColors(); clothNode.FixNormalMaps(); this.clothData.Add(new ClothData(clothNode, meshData)); } }
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); }
public static SCNVector4 GetVector(this SCNQuaternion self) { return(new SCNVector4(self.Xyz, self.W)); }
public static OpenTK.Quaternion ToQuaternion(this SCNQuaternion self) { return(new OpenTK.Quaternion(self.X, self.Y, self.Z, self.W)); }
public static SCNQuaternion Divide(this SCNQuaternion left, SCNQuaternion right) { return(SCNQuaternion.Multiply(left, SCNQuaternion.Invert(right))); }
public override void ViewDidLoad() { base.ViewDidLoad(); // Perform any additional setup after loading the view, typically from a nib. var scene = new SCNScene(); var rnd = new Random(); Func <int, int, bool, float> random = (min, max, clamp) => { float num = (float)((double)rnd.Next(min, max) * rnd.NextDouble()); if (!clamp) { return(num); } else if (num < 1.0f) { return(1.0f); } else { return(num); } }; Enumerable.Range(0, 200).Select <int, int> ((i) => Building( random(2, 5, true), random(2, 5, true), random(2, 10, true), random(-20, 20, false), random(-20, 20, false), scene, rnd )).ToArray(); //Lights! var lightNode = new SCNNode() { Light = new SCNLight(), Position = new SCNVector3(30.0F, 20.0F, 60.0F) }; lightNode.Light.LightType = SCNLightType.Omni; scene.RootNode.AddChildNode(lightNode); var ambientLightNode = new SCNNode() { Light = new SCNLight() }; ambientLightNode.Light.LightType = SCNLightType.Ambient; ambientLightNode.Light.Color = UIColor.DarkGray; scene.RootNode.AddChildNode(ambientLightNode); //Camera! var cameraNode = new SCNNode() { Camera = new SCNCamera() }; scene.RootNode.AddChildNode(cameraNode); cameraNode.Position = new SCNVector3(0.0F, 10.0F, 20.0F); var targetNode = new SCNNode() { Position = new SCNVector3(00.0F, 1.5F, 0.0F) }; scene.RootNode.AddChildNode(targetNode); var lc = SCNLookAtConstraint.Create(targetNode); cameraNode.Constraints = new[] { lc }; var scnView = new SCNView(UIScreen.MainScreen.Bounds) { Scene = scene, AllowsCameraControl = true, ShowsStatistics = true, BackgroundColor = UIColor.FromRGB(52, 152, 219) }; var floorNode = new SCNNode { Geometry = new SCNPlane { Height = 40.0F, Width = 40.0F }, Position = SCNVector3.Zero }; var pi2 = Math.PI / 2.0; floorNode.Orientation = SCNQuaternion.FromAxisAngle(SCNVector3.UnitX, (float)(0.0 - pi2)); scene.RootNode.AddChildNode(floorNode); var material = new SCNMaterial(); material.Diffuse.Contents = UIImage.FromFile("Content/road.jpg"); material.Diffuse.ContentsTransform = SCNMatrix4.Scale(new SCNVector3(10.0f, 10.0f, 1.0f)); material.Diffuse.MinificationFilter = SCNFilterMode.Linear; material.Diffuse.MagnificationFilter = SCNFilterMode.Linear; material.Diffuse.MipFilter = SCNFilterMode.Linear; material.Diffuse.WrapS = SCNWrapMode.Repeat; material.Diffuse.WrapT = SCNWrapMode.Repeat; material.Specular.Contents = UIColor.Gray; floorNode.Geometry.FirstMaterial = material; this.View = scnView; }
internal BoundingBoxSide(PositionName position, NVector3 extent, UIColor color = null) : base() { if (color == null) { color = Utilities.AppYellow; } Tiles = new List <Tile>(); this.color = color; this.face = position; // inline Swift setup() and setupExtensions() functions size = Size(extent); var yAxis = Axis.Y.Normal().ToSCNVector3(); var xAxis = Axis.X.Normal().ToSCNVector3(); var zAxis = Axis.Z.Normal().ToSCNVector3(); float halfTurn = (float)Math.PI; float quarterTurn = (float)Math.PI / 2; switch (face) { case PositionName.Front: LocalTranslate(new SCNVector3(0, 0, extent.Z / 2)); break; case PositionName.Back: LocalTranslate(new SCNVector3(0, 0, -extent.Z / 2)); LocalRotate(SCNQuaternion.FromAxisAngle(yAxis, halfTurn)); break; case PositionName.Left: LocalTranslate(new SCNVector3(-extent.X / 2, 0, 0)); LocalRotate(SCNQuaternion.FromAxisAngle(yAxis, -quarterTurn)); break; case PositionName.Right: LocalTranslate(new SCNVector3(extent.X / 2, 0, 0)); LocalRotate(SCNQuaternion.FromAxisAngle(yAxis, quarterTurn)); break; case PositionName.Bottom: LocalTranslate(new SCNVector3(0, -extent.Y / 2, 0)); LocalRotate(SCNQuaternion.FromAxisAngle(xAxis, halfTurn)); break; case PositionName.Top: LocalTranslate(new SCNVector3(0, extent.Y / 2, 0)); LocalRotate(SCNQuaternion.FromAxisAngle(xAxis, -quarterTurn)); break; } for (int index = 0; index < 12; index++) { var line = new SCNNode(); line.Geometry = Cylinder(lineThickness, extensionLength); if (index < 4) { xAxisExtLines.Add(line); line.LocalRotate(SCNQuaternion.FromAxisAngle(zAxis, -quarterTurn)); if (index == 2 || index == 3) { line.LocalRotate(SCNQuaternion.FromAxisAngle(xAxis, halfTurn)); } xAxisExtNode.AddChildNode(line); } else if (index < 8) { yAxisExtLines.Add(line); if (index == 5 || index == 7) { line.LocalRotate(SCNQuaternion.FromAxisAngle(xAxis, halfTurn)); } yAxisExtNode.AddChildNode(line); } else { zAxisExtLines.Add(line); line.LocalRotate(SCNQuaternion.FromAxisAngle(xAxis, -quarterTurn)); zAxisExtNode.AddChildNode(line); } } UpdateExtensions(); HideXAxisExtensions(); HideYAxisExtensions(); HideZAxisExtensions(); AddChildNode(xAxisExtNode); AddChildNode(yAxisExtNode); AddChildNode(zAxisExtNode); }
public SlingShotPose ComputeInputPose() { // note the -1 here differs from other usage var data = new SlingShotPose { UpVector = -this.UpVector /* negated because the strap Y-axis points down */ }; var startBend = this.CurrentLengthL / this.CurrentTotalLength; var endBend = 1f - this.CurrentLengthR / this.CurrentTotalLength; var leatherOnStraights = this.OriginalLeatherLength - this.CurrentLengthOnBall; var segmentAStart = 0f; var segmentAEnd = this.CurrentLengthL - leatherOnStraights * 0.5f; var segmentCStart = segmentAEnd + this.OriginalLeatherLength; var segmentCEnd = this.CurrentTotalLength; var originalLeatherRange = this.OriginalLeatherLength / this.OriginalTotalLength; var currentLeatherRange = this.OriginalLeatherLength / this.CurrentTotalLength; for (var i = 0; i < this.SimulatedTransformCount; i++) { var l = this.OriginalTotalLength * (float)i / (float)(this.SimulatedTransformCount - 1f); var u = l / this.OriginalTotalLength; // remap the u value depending on the material (rubber vs leather) var isRubber = Math.Abs(0.5f - u) > originalLeatherRange * 0.5f; if (isRubber) { if (u < 0.5f) { u = u / (0.5f - originalLeatherRange * 0.5f); u = (segmentAStart + (segmentAEnd - segmentAStart) * u) / this.CurrentTotalLength; } else { u = 1f - (1f - u) / (0.5f - originalLeatherRange * 0.5f); u = (segmentCStart + (segmentCEnd - segmentCStart) * u) / this.CurrentTotalLength; } } else { u = (startBend + endBend) * 0.5f - (0.5f - u) * (currentLeatherRange / originalLeatherRange); } var p = SCNVector3.Zero; var t = SCNVector3.UnitX; if (u < startBend) { // left straight var value = u / startBend; p = SimdExtensions.Mix(this.FixturePositionL, this.TangentPositionL, new SCNVector3(value, value, value)); // left rubber band t = SCNVector3.Normalize(this.TangentPositionL - this.FixturePositionL); } else if (u > endBend) { // right straight var value = (1f - u) / (1f - endBend); p = SimdExtensions.Mix(this.FixturePositionR, this.TangentPositionR, new SCNVector3(value, value, value)); // right rubber band t = SCNVector3.Normalize(this.FixturePositionR - this.TangentPositionR); } else { // on the ball var upv = this.UpVector; var rot = SCNQuaternion.FromAxisAngle(upv, -this.BetaAngle * (u - startBend) / (endBend - startBend)); p = this.ballPosition + rot.Act(this.TangentPositionL - this.ballPosition); t = SCNVector3.Cross(upv, SCNVector3.Normalize(this.ballPosition - p)); } data.Positions.Add(p); data.Tangents.Add(t); data.Lengths.Add(l); } return(data); }