Skip to content

Starfield 3D

Hapaxia edited this page Jun 3, 2023 · 2 revisions

Introduction

A class to draw a randomly generated 3D parallax starfield.

Starfield 3D creates a multitude of random stars within a specified sized rectangle. The maximum depth can also be specified. You can move amongst these stars in any direction within 3D space. You can also pan the view (effectively turning in that direction).

The stars can be any shape or colours; this is completely customisable. You can create a star template, which is a graphic made up of triangle, and all of the stars are drawn from this template. They can scale depending on their depth (customisable front and back scales) and/or fade their colour depending on their depth (customisable front and back colours). Colours are multiplied with the star template's colours.

The starfield can be moved infinitely and the stars will continuously (but randomly) wrap. Note that this means as soon as the stars leave the field, they won't arrive back in the same formation. However, the field can be much further than the actual given size (as it gets nearer).

The starfield is technically a cuboid that fits the greatest depth where it must match the given 2D size. This means that more and more of the field becomes out-of-view as it gets nearer and nearer. Note that this also means that a significant number of stars will often be "out-of-view" so more stars will be necessary to fill the view.

Note that stars can be drawn outside of the provided rectangle so clipping may be required if smaller than a window/viewport/render target.

Usage

Declaration

Any number of settings can be specified. They all have default settings.

The default settings are (and in order):

  • 0x0 size
  • 400 stars
  • maximum depth of 1,000,000
  • opaque white front colour
  • opaque black back colour
  • front scale of 1
  • back scale of 0

sw::Starfield3d starfield;
creates a starfield that has all default settings (see above).

sw::Starfield starfield(sf::Vector2f size, std::size_t numberOfStars, float maxDepth, sf::Color frontColor, sf::Color backColor, float frontScale, float backScale);
creates a starfield that specified all settings:

  • size is the 2D rectangle that is the visual target for the starfield to cover (this is a minimum rectangle, stars will likely also be drawn outside of this rectangle)
  • stars is the number of stars in the field. it's highly unlikely that all will be visible at once.
  • maxDepth is the maximum depth of the stars. this controls apparent depth/field of view.
  • frontColor is the colour in which the star template is multiplied with at the nearest positions.
  • backColor is the colour in which the star template is multiplied with at the furthest positions.

These two colours are "tweened" throughout the depths.

  • front scale is the scale of the star template at the nearest positions.
  • back scale is the scale of the star template at the furthest positions.

These two scales are "tweened" throughout the depths.

Drawing

This class inherits from sf::Drawable so it is drawn in the same way as all SFML drawables:
window.draw(starfield);
where window is an sf::RenderWindow.

Note: actually, window could be any sf::RenderTarget.

Transformations

This class inherits from sf::Transformable so it has all the usual SFML transformations available.

Manipulation

Set-up

  • regenerate(sf::Vector2f size, unsigned int numberOfStars)
    regenerates the stars with a new size and number of stars. Some of the parameters can be specified while leaving off others. New colours cannot be specified in a regeneration as the colours can be set separately without the need to regenerate. The combinations allowed are:
    () (no parameters)
    (size)
    (size, numberOfStars)
    (numberOfStars)

Depth

  • setMaxDepth(float maxDepth)
    sets the maximum depth value for the field.

  • setFrontColor(sf::Color color)
    sets the colour used for the nearest stars (multiplied with the colours used in the star template)

  • setBackColor(sf::Color color)
    sets the colour used for the furthest stars (multiplied with the colours used in the star template)

  • setFrontScale(float frontScale)
    sets the scale used for the nearest stars (scales the star template)

  • setBackScale(float backScale)
    sets the scale used for the furthest stars (scales the star template)

Star Template

Note the star template is made up of triangles (everything is drawn with the primitive sf::PrimitiveType::Triangles)

  • setStarTemplate(std::vector<sf::Vertex> vertices)
    sets the star template by copying the given vertices

  • setStarTemplate(std::vector<sf::Vector2f> vertices)
    sets the star template by copying the given vertices. These vertices are sf::Vector2f and represent only the positions part of the vertex. The colours will all be set to the default opaque white.

  • setStarTemplate(sf::VertexArray vertexArray)
    sets the star template by copying the given vertex array. Note that the primitive type is ignored as the Triangles primitive type will always be used.

Movement

  • move(sf::Vector3f)
    takes an sf::Vector3f and moves the 'viewer' in the direction of this vector as if moving the camera around. Note that this means, for example, moving to the right means the stars will move towards the left; this is the opposite effect from the simple Starfield drawable.

  • pan(sf::Vector2f)
    takes an sf::Vector2f and 'pans' the view in the direction of this vector as if turning the camera. Note that this means, for example, panning to the right means the stars will move towards the left. Panning has the effect of moving all of the stars at the same rate regardless of their depth.

Simple Example

#include <SelbaWard.hpp>
#include <SFML/Graphics.hpp>
int main()
{
    sf::ContextSettings contextSettings;
    contextSettings.antialiasingLevel = 16u;
    sf::RenderWindow window(sf::VideoMode(400u, 300u), "Starfield 3D simple example", sf::Style::Default, contextSettings);
    sw::Starfield3d starfield(sf::Vector2f(window.getSize()));
    starfield.setFrontScale(5.f);
    sf::Clock clock;
    while (window.isOpen())
    {
        sf::Event event; while (window.pollEvent(event)) if (event.type == sf::Event::Closed) window.close();
        const float frameTime{ clock.restart().asSeconds() };
        starfield.move({ frameTime * 100.f, 0.f, frameTime * 300.f });
        window.clear();
        window.draw(starfield);
        window.display();
    }
}

The code above displays something similar to:
Simple Example
The example animates (scrolls with parallax, including forward) the starfield, which cannot be seen in the screenshot.

Simple Example 2

#include <SelbaWard.hpp>
#include <SFML/Graphics.hpp>
int main()
{
    sf::ContextSettings contextSettings;
    contextSettings.antialiasingLevel = 16u;
    sf::RenderWindow window(sf::VideoMode(400u, 300u), "Starfield 3D simple example 2", sf::Style::Default, contextSettings);
    sw::Starfield3d starfield(sf::Vector2f(window.getSize()));
    starfield.setFrontScale(5.f);
    sf::Clock clock;
    float previousTime{ 0.f };
    while (window.isOpen())
    {
        sf::Event event; while (window.pollEvent(event)) if (event.type == sf::Event::Closed) window.close();
        const float time{ clock.getElapsedTime().asSeconds() };
        const float frameTime{ time - previousTime };
        previousTime = time;
        starfield.move({ frameTime * 100.f * -std::cos(time), 0.f, frameTime * 300.f * std::sin(time) });
        window.clear();
        window.draw(starfield);
        window.display();
    }
}

The code above displays something similar to:
Simple Example 2

Note that this GIF animation is looped so there is a noticeable jump when the animation restarts. This does not occur in the actual code.

(Starfield 3D v1.0)