Пример #1
0
        private void InitializeHelpers()
        {
            this.computedInputPose        = new ComputedValue <SlingShotPose>(() => this.ComputeInputPose());
            this.computedTangentPositionR = new ComputedValue <SCNVector3>(() => this.TangentPosition(this.FixturePositionR));
            this.computedTangentPositionL = new ComputedValue <SCNVector3>(() => this.TangentPosition(this.FixturePositionL));

            this.computedBetaAngle = new ComputedValue <float>(() =>
            {
                var d = SCNVector3.Normalize(this.ballPosition - this.CenterPosition);
                var t = SCNVector3.Normalize(this.TangentPositionL - this.ballPosition);

                var quaternion = SimdExtensions.CreateQuaternion(d, t);
                quaternion.ToAxisAngle(out SCNVector3 _, out float angle);
                return(2f * angle);
            });

            this.computedCenterPosition = new ComputedValue <SCNVector3>(() =>
            {
                var direction = SCNVector3.Cross(this.UpVector, this.TangentPositionR - this.TangentPositionL);
                return(this.ballPosition - SCNVector3.Normalize(direction) * 1.25f * this.ballRadius);
            });

            this.computedRestPose = new ComputedValue <SlingShotPose>(() =>
            {
                var data = new SlingShotPose();

                for (var i = 0; i < this.restPoseTransforms.Count; i++)
                {
                    var transform = this.restPoseSpace * this.restPoseTransforms[i];
                    var p         = new SCNVector3(transform.Column3.X, transform.Column3.Y, transform.Column3.Z);
                    var t         = SimdExtensions.CreateQuaternion(transform).Act(new SCNVector3(1f, 0f, 0f));

                    var l = 0f;
                    if (i > 0)
                    {
                        l = data.Lengths[i - 1] + (p - data.Positions[i - 1]).Length;
                    }

                    data.Positions.Add(p);
                    data.Tangents.Add(t);
                    data.Lengths.Add(l);
                }

                return(data);
            });
        }
Пример #2
0
        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);
        }