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))); }
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); }
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)); }
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; }
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)); }
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; }
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); }
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)); }
/// <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)); }
/// <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)); }
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)); }
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))); }
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)); }
/// <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)); }
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)); } } }); }