public void CyclicOffsetLoopBehavior()
        {
            var keyFrame0 = new KeyFrame <QuaternionF>(TimeSpan.FromSeconds(0.0), _random.NextQuaternionF());
            var keyFrame1 = new KeyFrame <QuaternionF>(TimeSpan.FromSeconds(1.0), _random.NextQuaternionF());
            var keyFrame2 = new KeyFrame <QuaternionF>(TimeSpan.FromSeconds(2.0), _random.NextQuaternionF());
            var animation = new QuaternionFKeyFrameAnimation();

            animation.KeyFrames.Add(keyFrame0);
            animation.KeyFrames.Add(keyFrame1);
            animation.KeyFrames.Add(keyFrame2);

            var animationClip = new AnimationClip <QuaternionF> {
                Animation = animation
            };

            animationClip.LoopBehavior = LoopBehavior.CycleOffset;
            animationClip.Duration     = TimeSpan.MaxValue;
            animationClip.ClipOffset   = TimeSpan.FromSeconds(-1);

            var defaultSource = _random.NextQuaternionF();
            var defaultTarget = _random.NextQuaternionF();

            // Pre loop
            var cycleOffset = keyFrame2.Value * keyFrame0.Value.Inverse;
            var expected    = InterpolationHelper.Lerp(keyFrame1.Value, keyFrame2.Value, 0.25f);

            Assert.IsTrue(QuaternionF.AreNumericallyEqual(expected, cycleOffset * animationClip.GetValue(TimeSpan.FromSeconds(0.25), defaultSource, defaultTarget)));

            // Post loop
            expected = cycleOffset * cycleOffset * InterpolationHelper.Lerp(keyFrame1.Value, keyFrame2.Value, 0.75f);
            Assert.IsTrue(QuaternionF.AreNumericallyEqual(expected, animationClip.GetValue(TimeSpan.FromSeconds(6.75), defaultSource, defaultTarget)));
        }
Beispiel #2
0
        public bool GetDisplacement(float x, float z, out Vector3F displacement, out Vector3F normal)
        {
            if (!EnableCpuQueries)
            {
                throw new InvalidOperationException("OceanWaves.GetDisplacement() can only be called if EnableCpuQueries is set to true.");
            }

            displacement = new Vector3F(0);
            normal       = new Vector3F(0, 1, 0);
            if (_h == null)
            {
                return(false);
            }

            float texCoordX = (x - TileCenter.X) / TileSize + 0.5f;
            float texCoordY = (z - TileCenter.Z) / TileSize + 0.5f;

            // Point sampling or bilinear filtering:
#if false
            // Convert to array indices.
            int xIndex = Wrap((int)(texCoordX * CpuSize));
            int yIndex = Wrap((int)(texCoordY * CpuSize));

            float    h = _h[xIndex, yIndex].X;
            Vector2F d = _D[xIndex, yIndex];
            Vector2F n = _N[xIndex, yIndex];
#else
            // Sample 4 values. The upper left index is (without wrapping):
            float xIndex = texCoordX * CpuSize - 0.5f;
            float yIndex = texCoordY * CpuSize - 0.5f;

            // Get the 4 indices.
            int x0 = Wrap((int)xIndex);
            int x1 = Wrap((int)xIndex + 1);
            int y0 = Wrap((int)yIndex);
            int y1 = Wrap((int)yIndex + 1);

            // Get fractions to use as lerp parameters.
            float px = MathHelper.Frac(xIndex);
            float py = MathHelper.Frac(yIndex);

            float h = InterpolationHelper.Lerp(InterpolationHelper.Lerp(_h[x0, y0].X, _h[x1, y0].X, px),
                                               InterpolationHelper.Lerp(_h[x0, y1].X, _h[x1, y1].X, px),
                                               py);

            Vector2F d = InterpolationHelper.Lerp(InterpolationHelper.Lerp(_D[x0, y0], _D[x1, y0], px),
                                                  InterpolationHelper.Lerp(_D[x0, y1], _D[x1, y1], px),
                                                  py);

            Vector2F n = InterpolationHelper.Lerp(InterpolationHelper.Lerp(_N[x0, y0], _N[x1, y0], px),
                                                  InterpolationHelper.Lerp(_N[x0, y1], _N[x1, y1], px),
                                                  py);
#endif

            displacement = new Vector3F(-d.X * Choppiness, h, -d.Y * Choppiness);

            normal   = new Vector3F(-n.X, 0, -n.Y);
            normal.Y = (float)Math.Sqrt(1 - normal.X * normal.X - normal.Y * normal.Y);
            return(true);
        }
Beispiel #3
0
        private float ComputeNoise(Vector2F position)
        {
            float t0  = position.X + N;
            int   bx0 = ((int)t0) & _maskB;
            int   bx1 = (bx0 + 1) & _maskB;
            float rx0 = t0 - (int)t0;
            float rx1 = rx0 - 1.0f;

            float t1  = position.Y + N;
            int   by0 = ((int)t1) & _maskB;
            int   by1 = (by0 + 1) & _maskB;
            float ry0 = t1 - (int)t1;
            float ry1 = ry0 - 1.0f;

            int b00 = _permutations[(_permutations[bx0] + by0) & _maskB];
            int b10 = _permutations[(_permutations[bx1] + by0) & _maskB];
            int b01 = _permutations[(_permutations[bx0] + by1) & _maskB];
            int b11 = _permutations[(_permutations[bx1] + by1) & _maskB];

            float sx = ComputeCubicSpline(rx0);

            float u = _magnitudes[b00] * Vector2F.Dot(_gradients[b00], new Vector2F(rx0, ry0));
            float v = _magnitudes[b10] * Vector2F.Dot(_gradients[b10], new Vector2F(rx1, ry0));
            float a = InterpolationHelper.Lerp(u, v, sx);

            u = _magnitudes[b01] * Vector2F.Dot(_gradients[b01], new Vector2F(rx0, ry1));
            v = _magnitudes[b11] * Vector2F.Dot(_gradients[b11], new Vector2F(rx1, ry1));
            float b = InterpolationHelper.Lerp(u, v, sx);

            float sy = ComputeCubicSpline(ry0);

            return(InterpolationHelper.Lerp(a, b, sy));
        }
Beispiel #4
0
        protected override void OnUpdate(TimeSpan deltaTime)
        {
            // A random new wind change is chosen at regular intervals.
            const float WindInterval = 3;

            _timeSinceWindChange += (float)deltaTime.TotalSeconds;
            if (_timeSinceWindChange > WindInterval)
            {
                _lastAngle           = _nextAngle;
                _lastSpeed           = _nextSpeed;
                _timeSinceWindChange = 0;

                // Get random target angle.
                float a = RandomHelper.Random.NextFloat(-1, 1);
                // Apply non-linear curve to make smaller changes more likely.
                a = (float)Math.Pow(a, 3);
                // Convert to angle and limit variation.
                _nextAngle = _lastAngle + ConstantsF.PiOver2 * a * DirectionVariation;

                // Get random target speed.
                float s = RandomHelper.Random.NextFloat(0, 1);
                _nextSpeed = MaxSpeed * (1 - s * SpeedVariation);
            }

            // Update current wind.
            float p     = _timeSinceWindChange / WindInterval;
            float speed = InterpolationHelper.Lerp(_lastSpeed, _nextSpeed, p);
            float angle = InterpolationHelper.Lerp(_lastAngle, _nextAngle, p);

            Wind = speed * Matrix33F.CreateRotationY(angle) * Vector3F.UnitX;
        }
Beispiel #5
0
        private void SetRandomColorAndAlpha(ModelNode model)
        {
            var randomColor3F = RandomHelper.Random.NextVector3F(0, 4);

            // Desaturate random color to avoid eye cancer. ;-)
            float luminance   = Vector3F.Dot(randomColor3F, GraphicsHelper.LuminanceWeights);
            var   randomColor = (Vector3)InterpolationHelper.Lerp(new Vector3F(luminance), randomColor3F, 0.5f);

            var randomAlpha = MathHelper.Clamp(RandomHelper.Random.NextFloat(0, 5), 0, 1);

            // Change the values of all effect parameters "InstanceColor" and "InstanceAlpha":
            foreach (MeshNode meshNode in model.GetDescendants().OfType <MeshNode>())
            {
                foreach (MaterialInstance materialInstance in meshNode.MaterialInstances)
                {
                    foreach (EffectBinding effectBinding in materialInstance.EffectBindings)
                    {
                        if (effectBinding.ParameterBindings.Contains("InstanceColor"))
                        {
                            effectBinding.Set("InstanceColor", randomColor);
                        }
                        if (effectBinding.ParameterBindings.Contains("InstanceAlpha"))
                        {
                            effectBinding.Set("InstanceAlpha", randomAlpha);
                        }
                    }
                }
            }
        }
        public void SamplingKeyFrames()
        {
            var keyFrame0 = new KeyFrame <QuaternionF>(TimeSpan.FromSeconds(1.0), _random.NextQuaternionF());
            var keyFrame1 = new KeyFrame <QuaternionF>(TimeSpan.FromSeconds(2.0), _random.NextQuaternionF());
            var keyFrame2 = new KeyFrame <QuaternionF>(TimeSpan.FromSeconds(3.0), _random.NextQuaternionF());
            var animation = new QuaternionFKeyFrameAnimation();

            animation.KeyFrames.Add(keyFrame0);
            animation.KeyFrames.Add(keyFrame1);
            animation.KeyFrames.Add(keyFrame2);

            var defaultSource = _random.NextQuaternionF();
            var defaultTarget = _random.NextQuaternionF();

            // Without interpolation
            animation.EnableInterpolation = false;
            Assert.AreEqual(keyFrame0.Value, animation.GetValue(TimeSpan.FromSeconds(1.0), defaultSource, defaultTarget));
            Assert.AreEqual(keyFrame0.Value, animation.GetValue(TimeSpan.FromSeconds(1.75), defaultSource, defaultTarget));
            Assert.AreEqual(keyFrame1.Value, animation.GetValue(TimeSpan.FromSeconds(2.0), defaultSource, defaultTarget));
            Assert.AreEqual(keyFrame1.Value, animation.GetValue(TimeSpan.FromSeconds(2.75), defaultSource, defaultTarget));
            Assert.AreEqual(keyFrame2.Value, animation.GetValue(TimeSpan.FromSeconds(3.0), defaultSource, defaultTarget));

            // With interpolation
            animation.EnableInterpolation = true;
            Assert.IsTrue(QuaternionF.AreNumericallyEqual(keyFrame0.Value, animation.GetValue(TimeSpan.FromSeconds(1.0), defaultSource, defaultTarget)));
            var expected = InterpolationHelper.Lerp(keyFrame0.Value, keyFrame1.Value, 0.75f);

            Assert.AreEqual(expected, animation.GetValue(TimeSpan.FromSeconds(1.75), defaultSource, defaultTarget));
            Assert.AreEqual(keyFrame1.Value, animation.GetValue(TimeSpan.FromSeconds(2.0), defaultSource, defaultTarget));
            expected = InterpolationHelper.Lerp(keyFrame1.Value, keyFrame2.Value, 0.75f);
            Assert.AreEqual(expected, animation.GetValue(TimeSpan.FromSeconds(2.75), defaultSource, defaultTarget));
            Assert.AreEqual(keyFrame2.Value, animation.GetValue(TimeSpan.FromSeconds(3.0), defaultSource, defaultTarget));
        }
Beispiel #7
0
        public static void GetSunlight(float altitude, float turbidity, Vector3D sunDirection,
                                       out Vector3F directSunlight, out Vector3F scatteredSunlight)
        {
            _spectrum.SetSolarSpectrum();

            sunDirection.TryNormalize();
            double cosZenith = sunDirection.Y;

            Vector3F direct, indirect;

            if (cosZenith > 0)
            {
                // Daylight - Sun is above horizon.
                double zenithAngle = Math.Acos(cosZenith);
                _spectrum.ApplyAtmosphericTransmittance(zenithAngle, turbidity, altitude, _spectrumDirect, _spectrumIndirect);
                direct   = _spectrumDirect.ToXYZ();
                indirect = _spectrumIndirect.ToXYZ();
            }
            else
            {
                // Twilight - Sun is below horizon.
                // We lookup luminance based on experimental results on cloudless nights.

                // Get sun angle in degrees for table lookup.
                float solarAltitude = (float)MathHelper.ToDegrees(Math.Asin(sunDirection.Y));

                // Get luminance from table (linearly interpolating the next two table entries).
                int   lower = (int)Math.Floor(solarAltitude);
                int   higher = (int)Math.Ceiling(solarAltitude);
                float a, b;
                TwilightLuminance.TryGetValue(lower, out a);
                TwilightLuminance.TryGetValue(higher, out b);
                float Y = InterpolationHelper.Lerp(a, b, solarAltitude - lower);

                // We use fixed chromacity values.
                float x = 0.2f;
                float y = 0.2f;

                // Convert xyY to XYZ.
                float X = x * (Y / y);
                float Z = (1.0f - x - y) * (Y / y);

                // Get sunlight from slightly above the horizon.
                const float  epsilon     = 0.001f;
                const double zenithAngle = ConstantsD.PiOver2 - epsilon;
                _spectrum.ApplyAtmosphericTransmittance(zenithAngle, turbidity, altitude, _spectrumDirect, _spectrumIndirect);
                direct   = _spectrumDirect.ToXYZ();
                indirect = _spectrumIndirect.ToXYZ();

                // Blend between table values and sunset light.
                float blend = MathHelper.Clamp(-solarAltitude / 5.0f, 0, 1);
                direct   = InterpolationHelper.Lerp(direct, new Vector3F(0, 0, 0), blend);
                indirect = InterpolationHelper.Lerp(indirect, new Vector3F(X, Y, Z), blend);
            }

            // Convert XYZ to RGB.
            directSunlight    = GraphicsHelper.XYZToRGB * direct;
            scatteredSunlight = GraphicsHelper.XYZToRGB * indirect;
        }
Beispiel #8
0
        private void RenderDebugInfo(RenderContext context)
        {
            _debugRenderer.Clear();
            _debugRenderer.DrawAxes(Pose.Identity, 0.5f, true);

            //_debugRenderer.DrawTexture(_cloudLayerNode._renderTarget, new Rectangle(1280-512, 0, 512, 512));

#if XBOX
            _debugRenderer.DrawText(_ephemeris.Time.DateTime.ToString());
#else
            _debugRenderer.DrawText(_ephemeris.Time.ToString());
#endif

            _debugRenderer.PointSize = 10;

            var extraterrestrialSunlight = Ephemeris.ExtraterrestrialSunlight;

            Vector3F sun;
            Vector3F ambient;
            Ephemeris.GetSunlight(_scatteringSky.ObserverAltitude, 2.2f, _scatteringSky.SunDirection, out sun, out ambient);

            var scatterSun     = _scatteringSky.GetSunlight() / _scatteringSky.SunIntensity * extraterrestrialSunlight;
            var scatterAmbient = _scatteringSky.GetAmbientLight(1024);
            scatterAmbient = scatterAmbient / _scatteringSky.SunIntensity * extraterrestrialSunlight;

            var scatterFog = _scatteringSky.GetFogColor(128) / _scatteringSky.SunIntensity * extraterrestrialSunlight;
            var luminance  = Vector3F.Dot(GraphicsHelper.LuminanceWeights, scatterFog);
            scatterFog = InterpolationHelper.Lerp(scatterFog, new Vector3F(luminance), 0.7f);

            _debugRenderer.DrawText("Extraterrestrial sun intensity:" + extraterrestrialSunlight.Length);
            _debugRenderer.DrawText("Spectrum sun intensity:" + sun.Length);
            _debugRenderer.DrawText("Scatter sun intensity:" + scatterSun.Length);

            _debugRenderer.DrawText("\nSpectrum ambient intensity:" + ambient.Length);
            _debugRenderer.DrawText("Scatter ambient intensity:" + scatterAmbient.Length);

            _debugRenderer.DrawText("\nScatter fog intensity:" + scatterFog.Length);

            _debugRenderer.DrawPoint(new Vector3F(-0.5f, 0, 0), new Color((Vector3)extraterrestrialSunlight.Normalized), true);

            sun.TryNormalize();
            ambient /= ambient.Length;
            _debugRenderer.DrawPoint(new Vector3F(0, 0, 0), new Color((Vector3)sun), true);
            _debugRenderer.DrawPoint(new Vector3F(0, -0.5f, 0), new Color((Vector3)ambient), true);

            scatterSun.TryNormalize();
            scatterAmbient.TryNormalize();
            _debugRenderer.DrawPoint(new Vector3F(0.5f, 0, 0), new Color((Vector3)scatterSun), true);
            _debugRenderer.DrawPoint(new Vector3F(0.5f, -0.5f, 0), new Color((Vector3)scatterAmbient), true);

            scatterFog.TryNormalize();
            _debugRenderer.DrawPoint(new Vector3F(0, 0.5f, 0), new Color((Vector3)scatterFog), true);

            _debugRenderer.PointSize = 40f;
            _debugRenderer.Render(context);
        }
Beispiel #9
0
        public void InterpolationTest()
        {
            var traits = QuaternionTraits.Instance;
            var value0 = (Quaternion)_random.NextQuaternionF();
            var value1 = (Quaternion)_random.NextQuaternionF();

            Assert.IsTrue(QuaternionF.AreNumericallyEqual((QuaternionF)value0, (QuaternionF)traits.Interpolate(value0, value1, 0.0f)));
            Assert.IsTrue(QuaternionF.AreNumericallyEqual((QuaternionF)value1, (QuaternionF)traits.Interpolate(value0, value1, 1.0f)));
            Assert.IsTrue(QuaternionF.AreNumericallyEqual(InterpolationHelper.Lerp((QuaternionF)value0, (QuaternionF)value1, 0.75f), (QuaternionF)traits.Interpolate(value0, value1, 0.75f)));
        }
        public void Lerp()
        {
            Assert.AreEqual(1.0f, InterpolationHelper.Lerp(1.0f, 2.0f, 0.0f));
            Assert.AreEqual(1.5f, InterpolationHelper.Lerp(1.0f, 2.0f, 0.5f));
            Assert.AreEqual(2.0f, InterpolationHelper.Lerp(1.0f, 2.0f, 1.0f));
            Assert.AreEqual(1.5f, InterpolationHelper.Lerp(2.0f, 1.0f, 0.5f));

            Assert.AreEqual(1.0, InterpolationHelper.Lerp(1.0, 2.0, 0.0));
            Assert.AreEqual(1.5, InterpolationHelper.Lerp(1.0, 2.0, 0.5));
            Assert.AreEqual(2.0, InterpolationHelper.Lerp(1.0, 2.0, 1.0));
            Assert.AreEqual(1.5, InterpolationHelper.Lerp(2.0, 1.0, 0.5));
        }
    public void AnimateUsingDefaults()
    {
      var defaultSource = _random.NextQuaternion();
      var defaultTarget = _random.NextQuaternion();

      var animation = new QuaternionFromToByAnimation();
      animation.From = null;
      animation.To = null;
      animation.By = null;
      Assert.AreEqual(defaultSource, animation.GetValue(TimeSpan.FromSeconds(0.0), defaultSource, defaultTarget));
      Assert.IsTrue(Quaternion.AreNumericallyEqual(InterpolationHelper.Lerp(defaultSource, defaultTarget, 0.75f), animation.GetValue(TimeSpan.FromSeconds(0.75), defaultSource, defaultTarget)));
      Assert.AreEqual(defaultTarget, animation.GetValue(TimeSpan.FromSeconds(1.0), defaultSource, defaultTarget));
    }
Beispiel #12
0
        /// <summary>
        /// Interpolates two poses.
        /// </summary>
        /// <param name="startPose">The start pose.</param>
        /// <param name="endPose">The end pose.</param>
        /// <param name="parameter">
        /// The interpolation parameter. If the value is 0, the <paramref name="startPose"/> is
        /// returned. If the value is 1, the <paramref name="endPose"/> is returned. For values between
        /// 0 and 1 an interpolated pose is returned.
        /// </param>
        /// <returns>An interpolated pose.</returns>
        public static Pose Interpolate(Pose startPose, Pose endPose, float parameter)
        {
            // Linearly interpolate position.
            var interpolatedPosition = startPose.Position * (1 - parameter) + endPose.Position * parameter;

            // Slerp orientation.
            var interpolatedOrientation = InterpolationHelper.Lerp(
                Quaternion.CreateFromRotationMatrix(startPose.Orientation),
                Quaternion.CreateFromRotationMatrix(endPose.Orientation),
                parameter);

            return(new Pose(interpolatedPosition, interpolatedOrientation));
        }
Beispiel #13
0
        /// <summary>
        /// Interpolates two poses.
        /// </summary>
        /// <param name="startPose">The start pose.</param>
        /// <param name="endPose">The end pose.</param>
        /// <param name="parameter">
        /// The interpolation parameter. If the value is 0, the <paramref name="startPose"/> is
        /// returned. If the value is 1, the <paramref name="endPose"/> is returned. For values between
        /// 0 and 1 an interpolated pose is returned.
        /// </param>
        /// <returns>An interpolated pose.</returns>
        public static PoseD Interpolate(PoseD startPose, PoseD endPose, double parameter)
        {
            // Linearly interpolate position.
            var interpolatedPosition = startPose.Position * (1 - parameter) + endPose.Position * parameter;

            // Slerp orientation.
            var interpolatedOrientation = InterpolationHelper.Lerp(
                QuaternionD.CreateRotation(startPose.Orientation),
                QuaternionD.CreateRotation(endPose.Orientation),
                parameter);

            return(new PoseD(interpolatedPosition, interpolatedOrientation));
        }
Beispiel #14
0
        public float GetValue(float frame)
        {
            if (Keys.Count == 0)
            {
                return(0);
            }

            float startFrame = Keys.First().Frame;

            Animation.KeyFrame LK = Keys.First();
            Animation.KeyFrame RK = Keys.Last();

            foreach (Animation.KeyFrame keyFrame in Keys)
            {
                if (keyFrame.Frame <= frame)
                {
                    LK = keyFrame;
                }
                if (keyFrame.Frame >= frame && keyFrame.Frame < RK.Frame)
                {
                    RK = keyFrame;
                }
            }

            if (LK.Frame != RK.Frame)
            {
                //  float FrameDiff = frame - LK.Frame;
                //  float Weight = 1.0f / (RK.Frame - LK.Frame);
                //  float Weight = FrameDiff / (RK.Frame - LK.Frame);

                float FrameDiff = frame - LK.Frame;
                float Weight    = FrameDiff / (RK.Frame - LK.Frame);

                Console.WriteLine($"frame diff {FrameDiff} frame {frame} LK {LK.Frame} RK {RK} ratio {Weight}");

                switch (InterpolationType)
                {
                case InterpolationType.CONSTANT: return(LK.Value);

                case InterpolationType.STEP: return(LK.Value);

                case InterpolationType.LINEAR: return(InterpolationHelper.Lerp(LK.Value, RK.Value, Weight));

                case InterpolationType.HERMITE:
                    float val = Hermite(frame, LK.Frame, RK.Frame, LK.In, LK.Out != -1 ? LK.Out : RK.In, LK.Value, RK.Value);
                    return(val);
                }
            }
            return(LK.Value);
        }
        public void LerpVector4()
        {
            Vector4 v       = new Vector4(1.0f, 10.0f, 100.0f, 1000.0f);
            Vector4 w       = new Vector4(2.0f, 20.0f, 200.0f, 2000.0f);
            Vector4 lerp0   = InterpolationHelper.Lerp(v, w, 0.0f);
            Vector4 lerp1   = InterpolationHelper.Lerp(v, w, 1.0f);
            Vector4 lerp05  = InterpolationHelper.Lerp(v, w, 0.5f);
            Vector4 lerp025 = InterpolationHelper.Lerp(v, w, 0.25f);

            Assert.AreEqual(v, lerp0);
            Assert.AreEqual(w, lerp1);
            Assert.AreEqual(new Vector4(1.5f, 15.0f, 150.0f, 1500.0f), lerp05);
            Assert.AreEqual(new Vector4(1.25f, 12.5f, 125.0f, 1250.0f), lerp025);
        }
        public void LerpVector3D()
        {
            Vector3D v       = new Vector3D(1.0, 10.0, 100.0);
            Vector3D w       = new Vector3D(2.0, 20.0, 200.0);
            Vector3D lerp0   = InterpolationHelper.Lerp(v, w, 0.0);
            Vector3D lerp1   = InterpolationHelper.Lerp(v, w, 1.0);
            Vector3D lerp05  = InterpolationHelper.Lerp(v, w, 0.5);
            Vector3D lerp025 = InterpolationHelper.Lerp(v, w, 0.25);

            Assert.AreEqual(v, lerp0);
            Assert.AreEqual(w, lerp1);
            Assert.AreEqual(new Vector3D(1.5, 15.0, 150.0), lerp05);
            Assert.AreEqual(new Vector3D(1.25, 12.5, 125.0), lerp025);
        }
    protected virtual void Update()
    {
        if (currentFrame <= frameDuration)
        {
            currentRange = InterpolationHelper.Lerp(startingRange, rangeTarget,
                                                    interpolationFunc.Transform((float)currentFrame / frameDuration));
            base.SetRange(currentRange);
        }
        else if (rangeTarget == 0 && isActiveAndEnabled)
        {
            base.Hide();
        }

        currentFrame += 1;
    }
    public void ShouldIgnoreByIfToIsSet()
    {
      var defaultSource = _random.NextQuaternion();
      var defaultTarget = _random.NextQuaternion();
      var to = _random.NextQuaternion();
      var by = _random.NextQuaternion();

      var animation = new QuaternionFromToByAnimation();
      animation.From = null;
      animation.To = to;
      animation.By = by;
      Assert.AreEqual(defaultSource, animation.GetValue(TimeSpan.FromSeconds(0.0), defaultSource, defaultTarget));
      Assert.IsTrue(Quaternion.AreNumericallyEqual(InterpolationHelper.Lerp(defaultSource, to, 0.75f), animation.GetValue(TimeSpan.FromSeconds(0.75), defaultSource, defaultTarget)));
      Assert.AreEqual(to, animation.GetValue(TimeSpan.FromSeconds(1.0), defaultSource, defaultTarget));
    }
    public void AnimateFromTo()
    {
      var defaultSource = _random.NextQuaternion();
      var defaultTarget = _random.NextQuaternion();
      var from = _random.NextQuaternion();
      var to = _random.NextQuaternion();
      var by = _random.NextQuaternion();

      var animation = new QuaternionFromToByAnimation();
      animation.From = from;
      animation.To = to;
      animation.By = null;
      Assert.AreEqual(from, animation.GetValue(TimeSpan.FromSeconds(0.0), defaultSource, defaultTarget));
      Assert.IsTrue(Quaternion.AreNumericallyEqual(InterpolationHelper.Lerp(from, to, 0.75f), animation.GetValue(TimeSpan.FromSeconds(0.75), defaultSource, defaultTarget)));
      Assert.AreEqual(to, animation.GetValue(TimeSpan.FromSeconds(1.0), defaultSource, defaultTarget));
    }
Beispiel #20
0
        public void Interpolate()
        {
            Pose p1 = new Pose(new Vector3(1, 2, 3), Quaternion.CreateRotationY(0.3f));
            Pose p2 = new Pose(new Vector3(-4, 5, -6), Quaternion.CreateRotationZ(-0.1f));

            Assert.IsTrue(Vector3.AreNumericallyEqual(p1.Position, Pose.Interpolate(p1, p2, 0).Position));
            Assert.IsTrue(Matrix.AreNumericallyEqual(p1.Orientation, Pose.Interpolate(p1, p2, 0).Orientation));

            Assert.IsTrue(Vector3.AreNumericallyEqual(p2.Position, Pose.Interpolate(p1, p2, 1).Position));
            Assert.IsTrue(Matrix.AreNumericallyEqual(p2.Orientation, Pose.Interpolate(p1, p2, 1).Orientation));

            Assert.IsTrue(Vector3.AreNumericallyEqual(InterpolationHelper.Lerp(p1.Position, p2.Position, 0.3f), Pose.Interpolate(p1, p2, 0.3f).Position));
            Assert.IsTrue(
                Quaternion.AreNumericallyEqual(
                    InterpolationHelper.Lerp(Quaternion.CreateFromRotationMatrix(p1.Orientation), Quaternion.CreateFromRotationMatrix(p2.Orientation), 0.3f),
                    Quaternion.CreateFromRotationMatrix(Pose.Interpolate(p1, p2, 0.3f).Orientation)));
        }
Beispiel #21
0
        public void Interpolate()
        {
            PoseD p1 = new PoseD(new Vector3D(1, 2, 3), QuaternionD.CreateRotationY(0.3));
            PoseD p2 = new PoseD(new Vector3D(-4, 5, -6), QuaternionD.CreateRotationZ(-0.1));

            Assert.IsTrue(Vector3D.AreNumericallyEqual(p1.Position, PoseD.Interpolate(p1, p2, 0).Position));
            Assert.IsTrue(Matrix33D.AreNumericallyEqual(p1.Orientation, PoseD.Interpolate(p1, p2, 0).Orientation));

            Assert.IsTrue(Vector3D.AreNumericallyEqual(p2.Position, PoseD.Interpolate(p1, p2, 1).Position));
            Assert.IsTrue(Matrix33D.AreNumericallyEqual(p2.Orientation, PoseD.Interpolate(p1, p2, 1).Orientation));

            Assert.IsTrue(Vector3D.AreNumericallyEqual(InterpolationHelper.Lerp(p1.Position, p2.Position, 0.3), PoseD.Interpolate(p1, p2, 0.3).Position));
            Assert.IsTrue(
                QuaternionD.AreNumericallyEqual(
                    InterpolationHelper.Lerp(QuaternionD.CreateRotation(p1.Orientation), QuaternionD.CreateRotation(p2.Orientation), 0.3),
                    QuaternionD.CreateRotation(PoseD.Interpolate(p1, p2, 0.3).Orientation)));
        }
        public void LerpQuaternion()
        {
            // Warning: The not all results are not verified
            Quaternion q1   = new Quaternion(1.0f, 2.0f, 3.0f, 4.0f).Normalized;
            Quaternion q2   = new Quaternion(2.0f, 4.0f, 6.0f, 8.0f).Normalized;
            Quaternion lerp = InterpolationHelper.Lerp(q1, q2, 0.75f);

            Assert.IsTrue(lerp.IsNumericallyNormalized);

            lerp = InterpolationHelper.Lerp(q1, q2, 0);
            Assert.IsTrue(Quaternion.AreNumericallyEqual(q1, lerp));

            lerp = InterpolationHelper.Lerp(q1, q2, 1);
            Assert.IsTrue(Quaternion.AreNumericallyEqual(q2, lerp));

            q1   = Quaternion.Identity;
            q2   = Quaternion.CreateFromRotationMatrix(Vector3.UnitZ, (float)Math.PI / 2);
            lerp = InterpolationHelper.Lerp(q1, q2, 0.5f);
            Vector3 v      = lerp.Rotate(Vector3.UnitX);
            Vector3 result = new Vector3(1.0f, 1.0f, 0.0f).Normalized;

            Assert.IsTrue(Vector3.AreNumericallyEqual(result, v));

            q1     = Quaternion.Identity;
            q2     = Quaternion.CreateFromRotationMatrix(Vector3.UnitY, (float)Math.PI / 2);
            lerp   = InterpolationHelper.Lerp(q1, q2, 0.5f);
            v      = lerp.Rotate(Vector3.UnitZ);
            result = new Vector3(1.0f, 0.0f, 1.0f).Normalized;
            Assert.IsTrue(Vector3.AreNumericallyEqual(result, v));

            q1     = Quaternion.Identity;
            q2     = Quaternion.CreateFromRotationMatrix(Vector3.UnitX, (float)Math.PI / 2);
            lerp   = InterpolationHelper.Lerp(q1, q2, 0.5f);
            v      = lerp.Rotate(Vector3.UnitY);
            result = new Vector3(0.0f, 1.0f, 1.0f).Normalized;
            Assert.IsTrue(Vector3.AreNumericallyEqual(result, v));

            q1     = new Quaternion(-1.0f, 0.0f, 0.0f, 0.0f);
            q2     = Quaternion.CreateFromRotationMatrix(-Vector3.UnitZ, (float)-Math.PI / 2);
            lerp   = InterpolationHelper.Lerp(q1, q2, 0.5f);
            v      = lerp.Rotate(Vector3.UnitX);
            result = new Vector3(1.0f, 1.0f, 0.0f).Normalized;
            Assert.IsTrue(Vector3.AreNumericallyEqual(result, v));
        }
        public void LerpQuaternionD()
        {
            // Warning: The not all results are not verified
            QuaternionD q1   = new QuaternionD(1.0, 2.0, 3.0, 4.0).Normalized;
            QuaternionD q2   = new QuaternionD(2.0, 4.0, 6.0, 8.0).Normalized;
            QuaternionD lerp = InterpolationHelper.Lerp(q1, q2, 0.75);

            Assert.IsTrue(lerp.IsNumericallyNormalized);

            lerp = InterpolationHelper.Lerp(q1, q2, 0);
            Assert.IsTrue(QuaternionD.AreNumericallyEqual(q1, lerp));

            lerp = InterpolationHelper.Lerp(q1, q2, 1);
            Assert.IsTrue(QuaternionD.AreNumericallyEqual(q2, lerp));

            q1   = QuaternionD.Identity;
            q2   = QuaternionD.CreateRotation(Vector3D.UnitZ, Math.PI / 2);
            lerp = InterpolationHelper.Lerp(q1, q2, 0.5);
            Vector3D v      = lerp.Rotate(Vector3D.UnitX);
            Vector3D result = new Vector3D(1.0, 1.0, 0.0).Normalized;

            Assert.IsTrue(Vector3D.AreNumericallyEqual(result, v));

            q1     = QuaternionD.Identity;
            q2     = QuaternionD.CreateRotation(Vector3D.UnitY, Math.PI / 2);
            lerp   = InterpolationHelper.Lerp(q1, q2, 0.5);
            v      = lerp.Rotate(Vector3D.UnitZ);
            result = new Vector3D(1.0, 0.0, 1.0).Normalized;
            Assert.IsTrue(Vector3D.AreNumericallyEqual(result, v));

            q1     = QuaternionD.Identity;
            q2     = QuaternionD.CreateRotation(Vector3D.UnitX, Math.PI / 2);
            lerp   = InterpolationHelper.Lerp(q1, q2, 0.5);
            v      = lerp.Rotate(Vector3D.UnitY);
            result = new Vector3D(0.0, 1.0, 1.0).Normalized;
            Assert.IsTrue(Vector3D.AreNumericallyEqual(result, v));

            q1     = new QuaternionD(-1.0, 0.0, 0.0, 0.0);
            q2     = QuaternionD.CreateRotation(-Vector3D.UnitZ, -Math.PI / 2);
            lerp   = InterpolationHelper.Lerp(q1, q2, 0.5);
            v      = lerp.Rotate(Vector3D.UnitX);
            result = new Vector3D(1.0, 1.0, 0.0).Normalized;
            Assert.IsTrue(Vector3D.AreNumericallyEqual(result, v));
        }
Beispiel #24
0
        /// <summary>
        /// Called to compute the fog intensity for <see cref="GetIntensity"/>.
        /// </summary>
        /// <param name="fogNode">The fog node. (Is never <see langword="null"/>.)</param>
        /// <param name="cameraNode">The camera node. (Is never <see langword="null"/>.)</param>
        /// <param name="targetPosition">The target position.</param>
        /// <returns>The fog intensity (0 = no fog; 1 = full fog, nothing else visible).</returns>
        /*protected virtual*/
        private float OnGetIntensity(FogNode fogNode, CameraNode cameraNode, Vector3 targetPosition)
        {
            // These computations are the same as in FogRenderer and the Fog shader files.

            if (Numeric.IsZero(Density))
            {
                return(0);
            }

            Vector3 cameraToPosition          = targetPosition - cameraNode.PoseWorld.Position;
            float   distance                  = cameraToPosition.Length; // The distance traveled inside the fog.
            Vector3 cameraToPositionDirection = cameraToPosition / distance;

            // Compute a value that is 0 at Start and 1 at End.
            float ramp = (distance - Start) / (End - Start);

            // Smoothstep distance fog
            float smoothRamp = InterpolationHelper.HermiteSmoothStep(ramp);

            // Exponential Fog
            float referenceHeight = cameraNode.PoseWorld.Position.Y - fogNode.PoseWorld.Position.Y
                                    + cameraToPositionDirection.Y * Start;
            float distanceInFog = distance - Start;
            var   fogDirection  = cameraToPositionDirection;

            if (HeightFalloff * fogDirection.Y < 0)
            {
                referenceHeight += fogDirection.Y * distanceInFog;
                fogDirection     = -fogDirection;
            }

            float referenceDensity = Density * (float)Math.Pow(2, -HeightFalloff * referenceHeight);
            float opticalLength    = GetOpticalLengthInHeightFog(distanceInFog, referenceDensity, fogDirection * distanceInFog, HeightFalloff);
            float heightFog        = (1 - (float)Math.Pow(2, -opticalLength * 1));

            // Get alpha from BottomColor and TopColor.
            // (Note: We have to avoid division by zero.)
            float height = targetPosition.Y - fogNode.PoseWorld.Position.Y;
            float p      = MathHelper.Clamp((height - Height0) / Math.Max(Height1 - Height0, 0.0001f), 0, 1);
            float alpha  = InterpolationHelper.Lerp(Color0.W, Color1.W, p);

            return(smoothRamp * heightFog * alpha);
        }
        private Vector3F GetBaseColor(Vector3F direction)
        {
            // 0 = zenith, 1 = horizon
            float p = 1 - MathHelper.Clamp(
                (float)Math.Acos(direction.Y) / ConstantsF.Pi * 2,
                0,
                1);

            var colorAverage = (BaseHorizonColor + BaseZenithColor) / 2;

            if (p < BaseColorShift)
            {
                return(InterpolationHelper.Lerp(BaseHorizonColor, colorAverage, p / BaseColorShift));
            }
            else
            {
                return(InterpolationHelper.Lerp(colorAverage, BaseZenithColor, (p - BaseColorShift) / (1 - BaseColorShift)));
            }
        }
        /// <summary>
        /// Gets the texture coordinates of the cloud texture in the specified direction.
        /// </summary>
        /// <param name="direction">The normalized direction.</param>
        /// <returns>
        /// The texture coordinates of the cloud texture. (The result is undefined if
        /// <paramref name="direction"/> does not point towards the sky.)
        /// </returns>
        public Vector2F GetTextureCoordinates(Vector3 direction)
        {
            float x = direction.X;
            float y = direction.Y + HorizonBias;
            float z = direction.Z;

            // We have to map the direction vector to texture coordinates.
            // fPlane(x) = x / y creates texture coordinates for a plane (= a lot of foreshortening).
            // fSphere(x) = x / (2 + 2 * y) creates texture coordinates for a paraboloid mapping (= almost no foreshortening).
            // fPlane(x) = x / (4 * y) is similar to fSphere(x) = x / (2 + 2 * y) for y near 1.
            Vector2F texCoord = InterpolationHelper.Lerp(
                new Vector2F(x / (4 * y), z / (4 * y)),
                new Vector2F(x / (2 + 2 * y), z / (2 + 2 * y)),
                SkyCurvature);

            Vector3 texCoord3F = new Vector3(texCoord.X, texCoord.Y, 1);

            texCoord3F = TextureMatrix * texCoord3F;
            return(new Vector2F(texCoord3F.X + 0.5f, texCoord3F.Y + 0.5f));
        }
        public void AnimateBy()
        {
            var defaultSource = _random.NextQuaternionF();
            var defaultTarget = _random.NextQuaternionF();
            var by            = _random.NextQuaternionF();

            var animation = new QuaternionFFromToByAnimation();

            animation.From = null;
            animation.To   = null;
            animation.By   = by;
            Assert.AreEqual(defaultSource, animation.GetValue(TimeSpan.FromSeconds(0.0), defaultSource, defaultTarget));
            Assert.IsTrue(QuaternionF.AreNumericallyEqual(InterpolationHelper.Lerp(defaultSource, by * defaultSource, 0.75f), animation.GetValue(TimeSpan.FromSeconds(0.75), defaultSource, defaultTarget)));
            Assert.AreEqual(by * defaultSource, animation.GetValue(TimeSpan.FromSeconds(1.0), defaultSource, defaultTarget));

            animation.By = by.Inverse;
            Assert.AreEqual(defaultSource, animation.GetValue(TimeSpan.FromSeconds(0.0), defaultSource, defaultTarget));
            Assert.IsTrue(QuaternionF.AreNumericallyEqual(InterpolationHelper.Lerp(defaultSource, by.Inverse * defaultSource, 0.75f), animation.GetValue(TimeSpan.FromSeconds(0.75), defaultSource, defaultTarget)));
            Assert.AreEqual(by.Inverse * defaultSource, animation.GetValue(TimeSpan.FromSeconds(1.0), defaultSource, defaultTarget));
        }
        public void OscillateLoopBehavior()
        {
            var keyFrame0 = new KeyFrame <QuaternionF>(TimeSpan.FromSeconds(1.0), _random.NextQuaternionF());
            var keyFrame1 = new KeyFrame <QuaternionF>(TimeSpan.FromSeconds(2.0), _random.NextQuaternionF());
            var keyFrame2 = new KeyFrame <QuaternionF>(TimeSpan.FromSeconds(3.0), _random.NextQuaternionF());
            var animation = new QuaternionFKeyFrameAnimation();

            animation.KeyFrames.Add(keyFrame0);
            animation.KeyFrames.Add(keyFrame1);
            animation.KeyFrames.Add(keyFrame2);

            var animationClip = new AnimationClip <QuaternionF> {
                Animation = animation
            };

            animationClip.LoopBehavior = LoopBehavior.Oscillate;
            animationClip.Duration     = TimeSpan.MaxValue;
            animationClip.ClipStart    = TimeSpan.FromSeconds(1.0);
            animationClip.ClipEnd      = TimeSpan.FromSeconds(3.0);
            animationClip.ClipOffset   = TimeSpan.FromSeconds(-11.0);

            var defaultSource = _random.NextQuaternionF();
            var defaultTarget = _random.NextQuaternionF();

            // Pre loop
            var expected = InterpolationHelper.Lerp(keyFrame0.Value, keyFrame1.Value, 0.75f);

            Assert.AreEqual(expected, animationClip.GetValue(TimeSpan.FromSeconds(10.25), defaultSource, defaultTarget));

            expected = InterpolationHelper.Lerp(keyFrame1.Value, keyFrame2.Value, 0.25f);
            Assert.AreEqual(expected, animationClip.GetValue(TimeSpan.FromSeconds(8.25), defaultSource, defaultTarget));

            // Post loop
            expected = InterpolationHelper.Lerp(keyFrame0.Value, keyFrame1.Value, 0.25f);
            Assert.AreEqual(expected, animationClip.GetValue(TimeSpan.FromSeconds(14.75), defaultSource, defaultTarget));

            expected = InterpolationHelper.Lerp(keyFrame1.Value, keyFrame2.Value, 0.75f);
            Assert.AreEqual(expected, animationClip.GetValue(TimeSpan.FromSeconds(16.75), defaultSource, defaultTarget));
        }
Beispiel #29
0
    private void Draw(ref EffectPassBinding passBinding, RenderContext context, int index, int count, RenderOrder order)
    {
      var jobs = _jobs.Array;
      var cameraNode = context.CameraNode;
      var cameraPose = cameraNode.PoseWorld;

      var graphicsDevice = context.GraphicsService.GraphicsDevice;

      // Flag: true if the box vertex/index buffers are not set in the graphics device.
      bool setBoxBuffers = true;

      foreach (var pass in passBinding)
      {
        for (int i = index; i < index + count; i++)
        {
          var materialInstanceBinding = jobs[i].MaterialInstanceBinding;
          var decalNode = jobs[i].DecalNode;
          var decalPose = decalNode.PoseWorld;

          // Update and apply local, per-instance and per-pass bindings.
          foreach (var binding in materialInstanceBinding.ParameterBindings)
          {
            if (binding.Description.Hint == EffectParameterHint.PerPass)
              binding.Update(context);

            binding.Apply(context);
          }

          pass.Apply();

          bool drawWithQuad = false;
          if (!ClipAtNearPlane)
          {
            // ----- Check if near plane intersects the decal box.

            // First make a simple AABB check in world space.
            if (GeometryHelper.HaveContact(_cameraNearPlaneAabbWorld, decalNode.Aabb))
            {
              // Make exact check of decal box against camera near plane AABB in camera space.
              var decalBoxExtent = new Vector3(1, 1, 1);
              decalBoxExtent *= decalNode.ScaleLocal;
              var decalBoxCenter = new Vector3(0, 0, -decalNode.ScaleLocal.Z / 2);

              // Get pose of decal box in view space.
              var decalBoxPose = new Pose(
                cameraPose.ToLocalPosition(decalPose.Position + decalPose.Orientation * decalBoxCenter),
                cameraPose.Orientation.Transposed * decalPose.Orientation);

              // Aabb of camera near plane in view space.
              var projection = cameraNode.Camera.Projection;
              var cameraNearPlaneAabb = new Aabb(
                new Vector3(projection.Left, projection.Bottom, -projection.Near),
                new Vector3(projection.Right, projection.Top, -projection.Near));

              drawWithQuad = GeometryHelper.HaveContact(cameraNearPlaneAabb, decalBoxExtent, decalBoxPose, true);
            }
          }

          if (!drawWithQuad)
          {
            // Draw a box primitive.

            if (setBoxBuffers)
            {
              graphicsDevice.SetVertexBuffer(_vertexBuffer);
              graphicsDevice.Indices = _indexBuffer;
              setBoxBuffers = false;
            }


            graphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, NumberOfPrimitives);
#else
            graphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, NumberOfVertices, 0, NumberOfPrimitives);

          }
          else
          {
            // Draw a quad at the near plane because the camera is inside the box. 
            // The quad vertices must be given decal space!

            var projection = cameraNode.Camera.Projection;
            Vector3 scale = decalNode.ScaleWorld;
            Pose cameraToDecalPose = decalPose.Inverse * cameraPose;

            Vector4 scissor = GraphicsHelper.GetBounds(cameraNode, decalNode);
            // Use a bias to avoid that this quad is clipped by the near plane.
            const float bias = 1.0001f;
            float left = InterpolationHelper.Lerp(projection.Left, projection.Right, scissor.X) * bias;
            float top = InterpolationHelper.Lerp(projection.Top, projection.Bottom, scissor.Y) * bias;
            float right = InterpolationHelper.Lerp(projection.Left, projection.Right, scissor.Z) * bias;
            float bottom = InterpolationHelper.Lerp(projection.Top, projection.Bottom, scissor.W) * bias;
            float z = -projection.Near * bias;
            _quadVertices[0] = cameraToDecalPose.ToWorldPosition(new Vector3(left, top, z));
            _quadVertices[0].X /= scale.X;
            _quadVertices[0].Y /= scale.Y;
            _quadVertices[0].Z /= scale.Z;
            _quadVertices[1] = cameraToDecalPose.ToWorldPosition(new Vector3(right, top, z));
            _quadVertices[1].X /= scale.X;
            _quadVertices[1].Y /= scale.Y;
            _quadVertices[1].Z /= scale.Z;
            _quadVertices[2] = cameraToDecalPose.ToWorldPosition(new Vector3(left, bottom, z));
            _quadVertices[2].X /= scale.X;
            _quadVertices[2].Y /= scale.Y;
            _quadVertices[2].Z /= scale.Z;
            _quadVertices[3] = cameraToDecalPose.ToWorldPosition(new Vector3(right, bottom, z));
            _quadVertices[3].X /= scale.X;
            _quadVertices[3].Y /= scale.Y;
            _quadVertices[3].Z /= scale.Z;

            graphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleStrip, _quadVertices, 0, 2, VertexPosition.VertexDeclaration);

            // Remember that the device vertex/index buffers are not set anymore.
            setBoxBuffers = true;
          }
        }
      }
    }
        private static void ClampHeightsToLineSegments(HeightField terrain, Aabb aabb, List <Vector4F> segments, float padding)
        {
            // TODO: Optimize this (see software rasterizers).

            float originX          = terrain.OriginX;
            float originZ          = terrain.OriginZ;
            int   numberOfSamplesX = terrain.NumberOfSamplesX;
            int   numberOfSamplesZ = terrain.NumberOfSamplesZ;
            int   numberOfCellsX   = numberOfSamplesX - 1;
            int   numberOfCellsZ   = numberOfSamplesZ - 1;
            float widthX           = terrain.WidthX;
            float cellSizeX        = widthX / numberOfCellsX;
            float widthZ           = terrain.WidthZ;
            float cellSizeZ        = widthZ / numberOfCellsZ;

            float[] heights = terrain.Samples;

            // Get min and max indices (inclusive).
            float minX = aabb.Minimum.X;
            float maxX = aabb.Maximum.X;
            float minZ = aabb.Minimum.Z;
            float maxZ = aabb.Maximum.Z;

            // Get min and max indices (inclusive).
            int indexXMin = Math.Max(0, (int)Math.Floor((minX - originX) / cellSizeX));
            int indexZMin = Math.Max(0, (int)Math.Floor((minZ - originZ) / cellSizeZ));
            int indexXMax = Math.Min(numberOfSamplesX - 1, (int)Math.Ceiling((maxX - originX) / cellSizeX));
            int indexZMax = Math.Min(numberOfSamplesZ - 1, (int)Math.Ceiling((maxZ - originZ) / cellSizeZ));

            Parallel.For(indexZMin, indexZMax + 1, indexZ =>
                         //for (int indexZ = indexZMin; indexZ <= indexZMax; indexZ++)
            {
                for (int indexX = indexXMin; indexX <= indexXMax; indexX++)
                {
                    Vector3F terrainPointFlat = new Vector3F(originX + cellSizeX * indexX, 0, originZ + cellSizeZ * indexZ);

                    float bestSegmentInfluence = 0;
                    float bestSegmentHeight    = 0;
                    for (int segmentIndex = 0; segmentIndex < segments.Count / 2; segmentIndex++)
                    {
                        var segmentStartFlat = new Vector3F(segments[segmentIndex * 2].X, 0, segments[segmentIndex * 2].Z);
                        var segmentEndFlat   = new Vector3F(segments[segmentIndex * 2 + 1].X, 0, segments[segmentIndex * 2 + 1].Z);
                        var segment          = new LineSegment(segmentStartFlat, segmentEndFlat);
                        float parameter;
                        GetLineParameter(ref segment, ref terrainPointFlat, out parameter);
                        Vector4F closestPoint     = segments[segmentIndex * 2] + parameter * (segments[segmentIndex * 2 + 1] - segments[segmentIndex * 2]);
                        Vector3F closestPointFlat = new Vector3F(closestPoint.X, 0, closestPoint.Z);
                        float distance            = (closestPointFlat - terrainPointFlat).Length - padding;
                        float influence           = MathHelper.Clamp(1 - distance / (closestPoint.W - padding), 0, 1);
                        if (influence > bestSegmentInfluence)
                        {
                            bestSegmentInfluence = influence;
                            bestSegmentHeight    = closestPoint.Y;
                        }
                    }

                    if (bestSegmentInfluence > 0)
                    {
                        heights[indexZ * numberOfSamplesX + indexX] = InterpolationHelper.Lerp(
                            heights[indexZ * numberOfSamplesX + indexX],
                            bestSegmentHeight,
                            InterpolationHelper.HermiteSmoothStep(bestSegmentInfluence));
                    }
                }
            });
        }