Posts mit dem Label Textures werden angezeigt. Alle Posts anzeigen
Posts mit dem Label Textures werden angezeigt. Alle Posts anzeigen

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.

4/29/2016

Where am i

In letzter Zeit habe ich sehr viel mit Three.js herumexperimentiert, aber ich habe es nie geschafft zumindest mal einen Teil der Experimente hier zu veröffentlichen.
Das wollte ich ändern und herausgekommen ist dabei „Where am i“. Im Prinzip eine sehr primitive Variante von Google Earth, umgesetzt mit Threejs und OpenStreetMap.
Mit Hilfe von „Where am i“ könnt ihr euch anzeigen lassen wo ihr gerade auf der Erde seid. Dazu stehen euch drei Methoden zur Auswahl.
Bei der ersten Methode („position“) liefert euch der Browser (ihr müsst ggf. zustimmen das der Browser euren Standort abfragen darf) automatisch die Daten um zu bestimmen wo ihr euch befindet.
Bei der zweiten Methode („name“) könnt ihr eine Stadt oder einen Ort angeben und OpenStreetMap liefert dann die entsprechenden Daten.
Und bei der dritten Methode („latitude & longitude“) könnt ihr euch per Eingabe von Breiten- und Längengrad eure Position auf der Erde anzeigen lassen.


Ihr könnt die Anwendung direkt hier starten, oder ihr öffnet „Where am i“ in einem neuen Browser-Fenster. Besonders zu empfehlen für Mobile User/Touch Devices!

Und hier noch ein paar kurze Infos zur Umsetzung.

Die meisten der hier eingesetzten Texturen bekommt ihr auf
Planet Texture Map Collection. Eine kleine aber feine und vor allem kostenlose Kollektion an guten Texturen für Planeten. Neben der üblichen ColorMap bekommt ihr hier auch noch BumpMap und SpecularMap mit dazu. Perfekt also für den Einsatz mit Three.js.

An die Daten von OpenStreetMap gelangt ihr wie folgt.
Um an Latitude und Longitude zu kommen per z.B. Städtename benutze ich diese Funktion hier:

function geocode( location ) {

    var geocode = 'http://nominatim.openstreetmap.org/search/' + encodeURI( location ) + '?format=json&polygon=1&addressdetails=1';

    $.getJSON( geocode, function( data ) {

        var lat = parseFloat( data[ 0 ].lat );
        var lon = parseFloat( data[ 0 ].lon );

        console.log( lat, lon );

    } );

};

Und umgekehrt funktioniert das auch. Nämlich mit dieser kleinen Funktion:

function geocodeReverse( lat, lon ) {

    var geocode = 'http://nominatim.openstreetmap.org/reverse?format=json&lat=' + lat + '&lon=' + lon + '&zoom=18&addressdetails=1';

    $.getJSON( geocode, function( data ) {

        var city = data.address.city;

        console.log( city );

    } );

};

Details dazu kann man sich hier durchlesen. Eine wirklich sehr gute Anleitung mit vielen Beispielen.
Wie ihr am Dollarzeichen sicher schon erkannt habt braucht ihr hierfür jQuery. Mit jQuery ist es einfach super komfortabel um an das JSON mit den Daten zu gelangen.

Und hier gibt es die Anleitung (mit Beispiel) wie ihr mit getCurrentPosition an die Positionsdaten des Clients/Device gelangt.

Die Umrechnung der Koordinaten von Breiten- und Längengrad in ein Sphärisches Koordinaten System erfolgt mit dieser Funktion hier:
function cartesianToSpherical( radius, lat, lon ) {

    var phi   = deg2rad( 90 - lat );
    var theta = deg2rad( lon + 180 );

    var x = -( radius * Math.sin( phi ) * Math.cos( theta ) );
    var z =  ( radius * Math.sin( phi ) * Math.sin( theta ) );
    var y =  ( radius * Math.cos( phi ) );

    return new THREE.Vector3( x, y, z );

};

function deg2rad( degAngle ) {

    return ( degAngle * Math.PI ) / 180;

};

Mehr dazu erfahrt ihr hier.
 

Und hier noch ein paar weitere sehr nützliche Links.
Wenn ihr euch für den Glow-Effekt um die Erde interessiert, dann schaut mal hier vorbei.
Und hier gibt es noch ein sehr gutes Beispiel wie ihr eine Sphere so drehen könnt, dass eine ausgewählte Koordinate auf der Sphere in Richtung der Kamera zeigt.
Die Animationen sind mit TwennLite von GreenSock umgesetzt.