Animierter Sternenhimmel mit Javascript Canvas Frameworks Javascript Canvas 

Animierter Sternenhimmel mit Javascript Canvas

Die Intros alter Star-Trek-Serien zeigen einen virtuellen Flug durch den Weltraum:

Ich mag diese Animation, denn sie ist einfach und trotzdem effektvoll. So etwas möchte ich mit Javascript Canvas programmieren. In diesem Tutorial erkläre ich Schritt für Schritt eine mögliche Lösung.

Vorbereitung

Zuerst lege ich den benötigten HTML-Code an. Er enthält das <canvas>-Tag, also die “Leinwand”, auf die ich später mit Javascript “zeichnen” werde. Ich speichere die Seite z.B. unter dem Namen “stars.html” (weitere Infos zum Umgang mit HTML-Dateien gibt es hier).

Im Head-Bereich verlinke ich die Javascript-Datei, in die ich den Code der Canvas-Animation einfügen werde. Die Datei befindet sich im gleichen Ordner wie die HTML-Datei.

<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="canvas_stars.js"></script>
</head>

<body style="background-color:#1d1d1d">

<canvas id="myCanvas" width="100" height="100" style="background-color: #1d1d1d">
Your browser does not support the HTML5 canvas tag.</canvas>

</body>
</html>

Als nächstes öffne ich die Javascript-Datei und füge folgende Anweisungen ein:

var c = document.getElementById('myCanvas');
c.width = window.innerWidth;
c.height = window.innerHeight;

var ctx = c.getContext('2d');

var Point = {
 x: 0,
 y: 0
};

Der Code sorgt als Erstes dafür, dass das Canvas die volle Breite und Höhe des Browserfensters (“window”) einnimmt. So lässt es sich besser in den Sternenhimmel eintauchen.

Mit dem Aufruf “getContext” erhalte ich ein Objekt, welches Anweisungen zum Zeichnen im Canvas entgegennimmt. Ich nenne es “ctx”.

Zum Schluss lege ich einen Objektprototyp “Point” an, der die x- und y-Koordinaten eines Punktes im Canvas zusammenfasst. Wie Sie weiter unten gleich sehen werden, spare ich mir damit den Aufwand, für die x- und y-Koordinaten ständig separate Variablen verwenden zu müssen.
 

Schritt 1: Eine Menge von Sternen generieren

Ich wähle einen objektorientierten Programmieransatz, d.h. mein Code soll Eigenschaften und Verhalten von Objekten aus der realen Welt modellieren. Meine Objekte sind die Sterne. Jeder Stern besitzt in meiner “Weltanschauung” zunächst zwei Eigenschaften, nämlich seine Position im Canvas (x- und y-Koordinaten) und seine Breite (wenn der Stern als Quadrat dargestellt wird). Das Verhalten eines Sterns ist seine Fähigkeit, sich selbst an der richtigen Stelle als Quadrat in das Canvas einzuzeichnen.

Nach dieser Analyse kann ein Prototyp für Stern-Objekte programmiert werden:

var Star = {
 position: null,
 width:3,
 
 draw: function() {

   ctx.beginPath();
   ctx.strokeStyle = 'hsl(60,100%,80%)';//Farbe des Sterns
 
   //Stern als Quadrat zeichnen:
   ctx.rect(this.position.x + c.width/2, this.position.y + c.height/2, this.width, this.width);

   ctx.stroke();
   ctx.closePath();
 }
};

Da es sich nur um einen Prototypen und noch nicht um einen konkreten Stern handelt, ist die Position noch undefiniert (null).

Der Koordinatenursprung (x=0,y=0) befindet sich in der linken oberen Ecke des Canvas. Um ihn in die Mitte des Canvas zu verschieben, addiere ich beim Zeichnen des Quadrats auf die x- und y-Koordinate jeweils die Hälfte der Breite bzw. Höhe des Canvas.

Als nächstes programmiere ich eine Funktion, die 250 Stern-Objekte (die Anzahl können Sie ändern) generiert und in einem Array mit dem Namen “stars” speichert:

var stars = [];

function createStars() {

 for (var i = 0; i< 250; i++) {

   //Erstelle Objekt nach der Vorlage des Prototyps "Star":
   var star = Object.create(Star);
   star.position = Object.create(Point);
   star.position.x = randomRange(-50, 50);
   stars.position.y = randomRange(-50, 50);
   
   stars.push(stars);
 }
}

function randomRange(minVal,maxVal) {
 return Math.floor(Math.random() * (maxVal-minVal-1)) + minVal;
}

Wie Sie sehen, wird die Position der Sterne zufällig generiert. Es ist wichtig, dass Positionen aus allen vier Quadranten des Koordinatensystems gewählt werden. Nur so ist es möglich, dass später die Sterne in alle vier Himmelsrichtungen schweben: Sterne im ersten Quadranten fliegen nach rechts oben, Sterne im zweiten Quadranten fliegen nach links oben usw..

Damit die generierten Sterne im Canvas angezeigt werden, brauche ich noch eine Funktion, die für alle Stern-Objekte die Funktion “draw” aufruft. Vorher wird mit dem Aufruf von “clearRect” das Canvas geleert.

function update() {

 ctx.clearRect(0, 0, c.width, c.height);

 stars.forEach(function(elem, i, arr) {
  
    elem.draw();
 });
}

createStars();
update();

Damit Sie das Ergebnis gleich sehen können, habe ich ein ausführbares Beispiel vorbereitet:



Your browser does not support the HTML5 canvas tag.

 

Schritt 2: Unterschiedliche Entfernungen definieren

Während der Animation müssen die Sterne schrittweise ihre Position im Canvas ändern. Dabei soll der Eindruck entstehen, dass die Sterne auf den Betrachter zu schweben. Mit anderen Worten: die Sterne sollen in einem virtuellen 3D-Raum eine bestimmte Entfernung vom Betrachter besitzen, und diese Entfernung soll sich Schritt für Schritt verringern.
 
Die folgende Skizze veranschaulicht den Sachverhalt nach den Grundsätzen der Zentralprojektion oder der perspektivischen Projektion. Der Bildschirm wird durch eine senkrechte Linie dargestellt. Er entspricht gleichzeitig der y-Achse. Davor befindet sich der Augpunkt O, an dem sich der Betrachter befindet. Dahinter befinden sich die Punkte P1 und P2 im virtuellen Raum. Um diese Punkte auf den Bildschirm zu projizieren, müssen die Schnittpunkte P1′ bzw. P2′ der Geraden OP1 bzw. OP2 mit dem Bildschirm berechnet werden. Es ist bereits erkennbar, dass ein Punkt, der dem Bildschirm bzw. dem Betrachter näher steht, auf der y-Achse weiter oben abgebildet wird (das gleiche gilt auch für die x-Achse). In ähnlicher Weise verhält sich die Star-Trek-Intro: die Sterne schweben langsam auf die Bildschirmränder zu.
 
Um die Projektionskoordinaten eines Punktes wie z.B. P1 zu berechnen, kann folgende Verhältnisgleichung (Strahlensatz) genutzt werden: P1.y/D = P1′.y/D’, sodass gilt: P1′.y = D’*P1.y/D
skizze
Im nächsten Schritt erweitere ich das Programm wie folgt:

  • Ich ergänze eine Konstante “d_strich” als Entfernung des Betrachters vom Schirm (ich wähle 150, den Wert können Sie ändern).
  • Ich ergänze eine Eigenschaft “d” im Star-Prototyp zur Festlegung der Entfernung des Sterns vom Betrachter.
  • Ich ergänze eine Funktion “project2d”, mit der die Bildschirmposition P’ eines Sterns P in Abhängigkeit von seiner Entfernung “d” berechnet werden kann.
  • Ich ändere die “draw”-Funktion so ab, dass der Stern P an die durch “project2d” berechnete Position P’ gezeichnet wird.
  • Beim Initialisieren der Stern-Objekte (“createStars”) erhält jeder Stern eine zufällig generierte Entfernung “d”. Meine Entfernungen liegen zwischen 0 und 32 Pixel, Sie können die Werte natürlich ändern.

 
Den geänderten Code zeige ich hier:



Your browser does not support the HTML5 canvas tag.

 

Schritt 3: Animation – die Sterne bewegen sich auf den Bildschirm zu

Jetzt ist alles vorbereitet, um eine Animation zu starten. Dazu sind nur noch drei Schritte erforderlich:

  1. Mit Hilfe der Canvas-Funktion “setInterval” veranlasse ich, dass meine Funktion “update” in einem bestimmten Intervall (z.B. alle 25ms) aufgerufen wird.
  2. In der Funktion “update” ergänze ich in der for-Schleife eine Anweisung, um die Entfernung “d” des Sterns “elem” zu reduzieren (z.B. um 0.2 Pixel). Das bedeutet, dass alle 25ms die Entfernung jedes Sterns um 0.2 Pixel reduziert wird (sie bewegen sich also auf den Betrachter zu).
  3. In der “draw”-Funktion veranlasse ich, dass ein Stern wieder auf die maximale Entfernung zurückgesetzt wird, sobald er den Rand des Canvas erreicht hat.



Your browser does not support the HTML5 canvas tag.

Hinweis: Wenn Sie mehrmals auf den “Ausführen”-Button klicken, kann es auf dieser Seite zu Problemen kommen.
 
So richtig schön sieht das Ganze noch nicht aus. Der 3D-Effekt wirkt erst dann, wenn sich Größe und Helligkeit der Sterne in Abhängigkeit von ihrer Entfernung ändern. Zu diesem Zweck berechne ich nun in der Funktion “draw” den Wert “percent”, der angibt, wie viel Prozent der maximalen Entfernung der Stern bereits zurückgelegt hat. Ich nutze ihn, um die Breite und Helligkeit des Sterns anzupassen.

 var percent = (1-this.d / max_dist);
 this.width = percent * 3;
 ..
 ctx.strokeStyle = 'hsl(60,100%,' + percent * 100 + '%)';
 



Your browser does not support the HTML5 canvas tag.

Hinweis: Wenn Sie mehrmals auf den “Ausführen”-Button klicken, kann es auf dieser Seite zu Problemen kommen.
 

Das Ergebnis auf Codepen

Die Sternenanimation stelle ich auch auf Codepen zur Verfügung:

See the Pen animated starfield by Anna Prenzel (@blaustern_fotografie) on CodePen.

Quellen

Blogbeitrag von Leonel Machava
PDF “Orthographic and perspective Projection”

Related posts

One thought on “Animierter Sternenhimmel mit Javascript Canvas

  1. Sehr super gemacht. Find ich gut!!

Comments are closed.