/// <summary>
        /// Computes the angular attenuation (spotlight falloff) for a given angle.
        /// </summary>
        /// <param name="angle">The angle relative to the main light direction in radians.</param>
        /// <param name="falloffAngle">The falloff angle.</param>
        /// <param name="cutoffAngle">The cutoff angle.</param>
        /// <returns>
        /// The angular attenuation of the light intensity. (1 when <paramref name="angle"/> is less
        /// than or equal to <paramref name="falloffAngle"/>. 0 when <paramref name="angle"/> is
        /// greater than or equal to <paramref name="cutoffAngle"/>.)
        /// </returns>
        /// <remarks>
        /// <para>
        /// The falloff between <paramref name="falloffAngle"/> and <paramref name="cutoffAngle"/> is
        /// computed using a smoothstep function (see
        /// <see cref="InterpolationHelper.HermiteSmoothStep(float)"/>).
        /// </para>
        /// <para>
        /// <i>angularAttenuation</i> = smoothstep((cos(<i>angle</i>) - cos(<i>cutoffAngle</i>)) /
        /// (cos(<i>falloffAngle</i>) - cos(<i>cutoffAngle</i>)))
        /// </para>
        /// </remarks>
        public static float GetAngularAttenuation(float angle, float falloffAngle, float cutoffAngle)
        {
            if (angle < 0)
            {
                angle = -angle;
            }

            if (angle <= falloffAngle)
            {
                return(1.0f);
            }

            if (angle >= cutoffAngle)
            {
                return(0.0f);
            }

            float cosOuterCone = (float)Math.Cos(cutoffAngle);
            float cosInnerCone = (float)Math.Cos(falloffAngle);
            float cosAngle     = (float)Math.Cos(angle);
            float cosDiff      = cosInnerCone - cosOuterCone;

            if (Numeric.IsZero(cosDiff))
            {
                return(0.0f);
            }

            float x = (cosAngle - cosOuterCone) / cosDiff;

            return(InterpolationHelper.HermiteSmoothStep(x));
        }
 public void HermiteSmoothStepF()
 {
     Assert.IsTrue(Numeric.AreEqual(0, InterpolationHelper.HermiteSmoothStep(-1.0)));
     Assert.IsTrue(Numeric.AreEqual(0, InterpolationHelper.HermiteSmoothStep(0.0)));
     Assert.IsTrue(Numeric.AreEqual(0.5, InterpolationHelper.HermiteSmoothStep(0.5)));
     Assert.IsTrue(Numeric.AreEqual(1, InterpolationHelper.HermiteSmoothStep(1.0)));
     Assert.IsTrue(Numeric.AreEqual(1, InterpolationHelper.HermiteSmoothStep(2.0)));
     Assert.IsTrue(Numeric.AreEqual(1 - InterpolationHelper.HermiteSmoothStep(1 - 0.3), InterpolationHelper.HermiteSmoothStep(0.3)));
     Assert.Greater(InterpolationHelper.HermiteSmoothStep(1 - 0.3), InterpolationHelper.HermiteSmoothStep(0.3));
 }
Example #3
0
        // Returns the flow vector for a given position.
        // x and y are in the range [0, 1].
        private static void GetFlow(Vector2F position, out Vector2F direction, out float speed)
        {
            // Create a circular movement around (0.5, 0.5).

            // Vector from center to position is:
            var radius = position - new Vector2F(0.5f, 0.5f);

            // The flow direction is orthogonal to the radius vector.
            direction = new Vector2F(radius.Y, -radius.X);
            direction.TryNormalize();

            // The speed is max in the center and is 0 at the texture border.
            speed = 1;
            if (!Numeric.IsZero(radius.Length))
            {
                speed = 1 - InterpolationHelper.HermiteSmoothStep(MathHelper.Clamp((radius.Length - 0.1f) / 0.4f, 0, 1));
            }
        }
Example #4
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 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));
                    }
                }
            });
        }