15 Jun 2018

Scenic screen saver

Includes simulated ropes, a sunset/sunrise model, and Perlin coherent noise

Overview

A video may be seen here.

The original goal was to simulate a rope; however, once the rope/swing was made then the project unintentionally grew to something much larger. Since I had just created a random tree generator, I thought it would be fun to anchor the simulated rope on the branches. Even cooler, let’s move the rope according to some fictitious wind force which introduced the need for the Perlin noise generator. The project grew to include a simulated sunset/sunrise (which I have been wanting to do for quite some time now), lightning bugs, an owl, blades of grass, stars, and a moon to make the scenery more interesting.

Ropes may be simulated by connecting masses to springs, and then one or both ends of the rope-object may be anchored. When both sides are anchored and all masses are in the presence of gravity, the proper catenary curve is reproduced which is a canonical calculus of variations result (hyperbolic cosine). Implementing a rope simulation in C++ is well described by this site, and will not be described in detail here. In short, though, the idea is to build a Mass class where the position may be updated as

void Mass::simulate(float dt){
  fVel.x += (fForce.x / fMass) * dt;
  fVel.y += (fForce.y / fMass) * dt;
  fPos.x += fVel.x * dt;
  fPos.y += fVel.y * dt;
}

void Mass::applyForce(sf::Vector2f force){
  fForce.x += force.x;
  fForce.y += force.y;
}

where dt is the intrinsic delta time in between frames (SFML provides sf::Clock and sf::Time classes for this purpose). Then, a Spring class is made where one spring is connected to two Mass-objects, and a spring force is used to constrain/connect the two masses; in this case, is an adjustable parameter, is the distance between the two masses, and is the length of the spring in absence of forces. This is where the Mass::applyForce(sf::Vector2f) comes in handy, which may also be used for gravity, air friction, or anything else that comes to mind to alter the behavior. A Rope-object is then built out of many Spring classes to realistically simulate the movement of a rope. The rope is continuously perturbed by a Perlin coherent noise generator to simulate the effects of wind. Note that the anchor points need to be updated according to the perturbations of the fractal tree.

The generation of the sunset was computationally expensive, and I learned how to do it here, which includes Mie and Rayleigh scattering models. The calculation needs to be performed for many angles (depending on the location of the sun relative to a viewer on Earth) in order to simulate a sunset/sunrise. I generated roughly 360 images, and the screen saver cycles through each image approximately every 0.5 seconds.

The remainder of the scenery, excluding the tire and owl sprites, were made completely with SFML vertex arrays. The random tree fractal generator is described in a previous post; the blades of grass use the same fundamental construction (built using a class that accepts 2 points for the bottom/top center points of a box, a width parameter, and a parameter to change the width ratio of the top relative to the bottom) in order to create the gradient effect. The alpha component of a blade is adjusted once the scenery is determined to be dark. The moon is actually 100 sf::CircleShapes where the alpha component is adjusted to give the glow effect. The bugs are black circles which randomly glow (the glow lasts for a time that is randomly determined by a Gaussian distribution); the glow becomes more frequent during the night time. The cricket noise was downloaded from here, and the volume increases at night. Just about the entire scenery (excluding the sprites and the sunset) are randomly generated and positioned, either using a flat or normal distribution using C++11’s random-class, which yields variations of the same screen-saver idea.

-->