5/08/2017

Pure JavaScript planetoid particles with light source and bumpmapping

Die Idee für dieses Experiment kam mir als ich bei Oleg Pashkovsky die „Animation with code #12“ sah und mich an ein älteres meiner Experimente erinnerte.
Das Ziel war nun eine Art Kombination beider Experimente. Ich wollte es ermöglichen einen ähnlichen Look zu erhalten wie bei Oleg und gleichzeitig verschiedene Planetoiden im dreidimensionalen Raum zu visualisieren.
Mit meinen vergangenen 3D Partikelexperimenten war bereits der Grundstein gelegt. Es blieb nur ein großes Problem. Für die Szene brauchte ich eine Lichtquelle. Und genau eine solche Lichtquelle hatte ich bisher noch nicht in meine Experimente mit implementiert. Da ich bei den Canvas Experimenten auf 3D Frameworks wie z.B. Three.js verzichte, musste ich eine Lösung finden das Ganze von Grund auf neu zu schreiben. Mein Glück, ich hatte noch das Buch „Foundation HTML5 Animation with JavaScript“
(Affiliatelink) von Keith Peters im Bücherregal stehen. Hier fand ich einen simplen Ansatz für eine rudimentäre Umsetzung einer Lichtquelle die nicht zu viel Rechenleistung beansprucht. 
var dotProd = particle.vx * light.x + particle.vy * light.y + particle.vz * light.z;

var normMag = Math.sqrt( particle.vx * particle.vx + particle.vy * particle.vy + particle.vz * particle.vz );

var lightMag = Math.sqrt( light.x * light.x + light.y * light.y + light.z * light.z );

var lightFactor = ( Math.acos( dotProd / ( normMag * lightMag ) ) / Math.PI ) * light.brightness;
Darüber hinaus sind in diesem Experiment weitere Neuerungen zu sehen die ich so bisher noch nicht umgesetzt hatte. Wenn man sich den Erdball aus meinem alten Experiment anschaut, dann sieht man die wenig schöne Verteilung der Partikel zur Abbildung des Planetoiden. Die jetzige Verteilung der Partikel ist da deutlich homogener. Aber auch hierbei gab es ein Problem. Die Platzierung der Partikel war Abhängig von den Koordinaten der Textur. Die damals eingesetzte Methode um Pixel-Koordinaten in Latitude und Longitude umzurechnen und dann auf eine Sphere zu mappen war also hinfällig. Die Lösung war der umgekehrte Weg. Ich erstelle die Sphere für den Planetoiden und hole mir dann erst die nötigen Pixel-Koordinaten zum Auslesen der Farbwerte aus der Textur. Die Lösung hierfür sind UV-Koordinaten. Mit erstaunlich wenig Mathe kommt man auf diesem Weg an 2D Koordinaten aus einer 3D-Sphere. 
p = p.normalize();

var u = Math.atan2( p.x, p.z ) / ( 2 * Math.PI ) + 0.5; 
var v = Math.asin( p.y ) / Math.PI + 0.5;

var x = u * texture.width;
var y = v * texture.height;
Und zu guter Letzt wollte ich dann noch Bumpmapping implementieren, damit die Oberfläche der Planetoiden plastischer und detailreicher erscheint. Normalerweise geschieht das über eine Bumpmap, oder auch height map genannt. Ich bin für dieses Experiment aber einen ganz anderen Weg gegangen. Ich berechne für jedes Partikel einen Wert, der auf der Basis der Farbe des Partikels basiert. Daraus ergibt sich ein Prozentwert. Eine Art Schwellenwertverfahren. Weiß ist also 100% und schwarz ist 0%. Mit einer simplen Formel multipliziere ich jetzt diesen Prozentwert in Kombination mit einer Variablen für die Stärke des Effekts zu den Koordinaten der Partikel. Auf diese Weise bekommen hellere Partikel einen größeren Radius als dunkle Partikel. Ein z.B. ein dunkles Tal auf dem Planetoiden ist somit also tatsächlich tiefer als ein heller Berg. Im Gegensatz zum klassischen Bumpmapping nehme ich in diesem Experiment also sehr wohl Einfluss auf die Geometriekomplexität. Da ich aber keinen Namen für diesen von mir eingesetzten Weg habe wird hier einfach, und vielleicht fälschlicher Weise, von Bumpmapping gesprochen.
var threshold = ( particle.color.r + particle.color.g + particle.color.b ) / 3;

var percent = threshold / 255;

var distance = ( percent / bumpScale ) + 1;

particle.x *= distance;
particle.y *= distance;
particle.z *= distance;

Genug erzählt. Komment wir endlich zum Experiment. Ich empfehle wie immer das Experiment in einem neuen Browser Tab zu öffnen. Ihr könnt es euch aber auch gleich hier unterhalb auf dieser Seite anschauen. Über den Button „Open Controls“ könnt ihr diverse Einstellungen vornehmen und verschiedene Texturen laden.




Die kleine Sphere in diesem Experiment symbolisiert die Lichtquelle. Verschwindet diese Lichtquelle hinter dem Planetoiden wird sie durch ein kleines rotes Kreuz visualisiert.
Ihr könnt mit Hilfe der Einstellungen die Anzahl der Partikel auf bis zu 125000 steigern. Auf diese Weise lässt dich der Detailgrad erhöhen, aber dafür kann die Performance leiden. Falls euer Rechner schon etwas älter ist könnte es also auch sinnvoll sein die Anzahl zu verringern. Ansonsten könnt ihr, wie bei meinen anderen Experimenten auch, die Szene abhängig von eurer Mausposition drehen. Für User mit mobilen Geräten und Touchscreen sind Touch-Events implementiert mit denen ihr die Szene ebenfalls steuern könnt. 

Die Texuren für den Planetoiden kommen von Planet Texture Maps und von Robert Stein III. Die Texturen habe ich lediglich in der Größe angepasst. Ansonsten entsprechen sie den Originalgrafiken.
Verlinkungen zu Amazon in diesem Blogpost sind so genannte Affiliate Links.

Keine Kommentare: