3D-"Flächenmodelle" mit unterschiedlicher "Lightness" zeichnen

Das Problem

Hue (0...360):    Saturation: Rotation   
Lightness von  %  bis   %

Auf der Seite "Hidden lines", "Edges", "Silhouette lines", "Lightness" wird das Problem behandelt, bei Darstellung von Flächenmodellen die Kanten sichtbar werden zu lassen an den Stellen, wo zwei Flächen zusammenstoßen. Die Möglichkeiten, den Flächen unterschiedliche Farben zu geben und/oder die Kanten mit einer anderen Farbe "nachzuzeichnen", wurden auf der Seite 3D-"Flächenmodelle" in geeigneter Reihenfolge zeichnen demonstriert, auf der auch gezeigt wird, wie das Problem der verdeckten Kanten und Flächen gelöst werden kann.

Weil die Lösungen "Unterschiedliche Farben" und "Kanten nachzeichnen" dann unbefriedigend sind, wenn ein einfarbiger Körper dargestellt werden soll, sieht man nebenstehend eine Variante, die der Realität näher kommt: Ein Ikosaeder mit einer Oberfläche aus 20 blauen Dreiecken wird von einer imaginären Lichtquelle beleuchtet, und die Helligkeit (Lightness), mit der die Flächen dargestellt werden, hängt von ihrer aktuellen Lage bezüglich dieser Lichtquelle ab.

HSL-Farbmodell

Canvas unterstützt neben dem RGB-Farbmodell (siehe Seite "Farben in CanvasGI") auch das HSL-Farbmodell, das für die Realisierung des Zeichnens der Flächen mit unterschiedlicher Helligkeit benutzt wird. In diesem Farbmodell wird die Farbe durch die Angabe der drei Eigenschaften "Farbton" ("Hue"), "Sättigung" ("Saturation") und "Helligkeit" ("Lightness") festgelegt:

Die Abgrenzung der einzelnen Flächen voneinander in der Animation oben rechts erfolgt ausschließlich über die Eigenschaft "Lightness". Dabei wird folgende Strategie realisiert:

Für das Erzeugen der Animation, die oben rechts zu sehen ist, gilt alles, was auf den Seiten "3D-Flächenmodelle in geeigneter Reihenfolge zeichnen" und "Mehrere 3D-Flächenmodelle zeichnen und animieren" ausführlich beschrieben wird. Deshalb kann der nachfolgende Überblick über den Rest der hier beschriebenen Grafik kurz ausfallen:

      function init () {

         gi = new canvasGI ("canvas") ;        // Ein "CanvasGI-Objekt" wird erzeugt
         xyz  = ikosaxyz  ;                    // Beim Start soll ein Ikosaeder ...
         area = ikosaarea ;                    // erscheinen

         NewParam () ;                         // ... liest Eingabefelder aus und zeichnet das Modell
         phiplus (gi.AXIS_Y);                  // ... startet die Animation (Rotation um y-Achse)
      }
      function NewParam (newtype) {

         var lmi = parseFloat (document.eingabe.Lummin.value) ;      // ... Lesen der Eingabefelder
         var lma = parseFloat (document.eingabe.Lummax.value) ;
         var hu  = parseFloat (document.eingabe.Hue.value)    ;
         var sv  = parseFloat (document.eingabe.Satur.value)  ;

         if (lmi < 0 || lma < lmi || lma > 100) {                    // ... Eingabewerte werden auf
            alert ("Luminanzwerte sind nicht korrekt!") ;            //     Einhaltung der Grenzen geprueft ...
            return ;
         }
         if (hu < 0 || lma > 360) {
            alert ("Hue-Wert muss im Bereich 0 ... 360 liegen!") ;
            return ;
         }
         if (sv < 0 || sv > 100) {
            alert ("Saturation muss im Bereich 0 ... 100% liegen!") ;
            return ;
         }

         lummin = lmi ;                                              // ... und schliesslich globalen
         lummax = lma ;                                              //     Variablen zugewiesen
         hueval = hu  ;
         satval = sv  ;

         var limits = gi.ptlimits (xyz) ;                            // .... Grenzen der 2D-Darstellung
         gi.setusercoordsi (limits.xumin , limits.yumin , limits.xumax , limits.yumax , 8) ;
         draw () ;
      }
      function draw () {

         gi.arealight (area , xyz , hueval , lummin , lummax , satval) ; // ... setzt Farbe nach HSL

         var points = new Array () ;                    // ... fuer die Koordinaten eines Polygons
         gi.clearcanvas ("silver" , "black") ;          // ... fuellt Canvas-Bereich mit Hintergrundfarbe
                                                        //     ("silver") und zeichnet schwarzen Rahmen
         for (var i = 0 ; i < area.length ; i++) {
            var np = area[i].length - 1 ;               // ... weil letztes Element die Farbe ist
            for (var j = 0 ; j < np ; j++) {
               points[j] = xyz[area[i][j]] ;            // ... sammelt Punktkoordinaten eines Polygons
            }
            area[i].unshift (gi.wtsymbdist (points , np)) ;  // ... berechnet symbolischen Abstand vom Betrachter
         }                                              //     und fuegt diesen Wert an der Array-Spitze an

         gi.sortbyindex (area , 0) ;                    // ... sortiert nach den Werten an der Array-Spitze

         for (var i = 0 ; i < area.length ; i++) {
            area[i].shift() ;                           // ... entfernt den Wert an der Array-Spitze wieder
            var np = area[i].length - 1 ;
            for (var j = 0 ; j < np ; j++) {
               points[j] = xyz[area[i][j]] ;            // ... sammelt Punktkoordinaten eines Polygons
            }
            gi.wtdrawcolarea (points , np , area[i][np]) ;  // ... coloriert eine Fläche 
         }
      }

Die letzte Aktion in der Start-Funktion init ist der Aufruf der Funktion phiplus. Diese startet mit window.setInterval sofort eine Animation, indem alle dT Tausendstel-Sekunden (dT ist global mit dem Wert dT = 50 vereinbart) die Funktion rotation gestartet wird:

      function rotation () {
         gi.t3rotation  (dPhi , rotax) ;
         gi.clearcanvas ("silver" , "black") ;
         draw () ;
      }

      function phiplus (axis) {
         rotax = axis ;
         if (anim == 1) {
            window.clearInterval (aktiv) ;
         }
         anim  = 1    ;
         aktiv = window.setInterval("rotation ()", dT);
      }

Beipiel-Programm "Polyarea 2"

Das Beipiel-Programm "Polyarea 2" enthält neben den oben beschriebenen Funktionen noch wesentlich mehr Angebote. Es startet mit folgendem Bild:

Weiterlesen