Materialien

Eines der mächtigsten Features von A6 ist die Fähigkeit, Materialien zu definieren. Der Unterschied zwischen A5 und A6 in diesem Bereich mag nicht sehr offensichtlich sein, aber er ist sehr groß. Sehen Sie sich diesen Screenshot an:

Glauben Sie mir wenn ich sage, dass Sie oben immer dasselbe Model, jeweils ein Klon vom “normalen” Kristall sehen, die nur verschiedene Materialien verwenden? Das heißt, dass ich nur ein einziges Model verwendet habe, mit einer einzigen Skin und das Aussehen nur durch Änderung einer Variablen ändern konnte. Es gibt wirklich keine Grenzen! Und hier kommt noch eine gute Nachricht: dieses Projekt erlaubt Ihnen, jedes Material herzustellen, das Sie sich vorstellen können.

Sehen wir uns an, was diese Demo kann; öffnen Sie materials.wmp, lassen Sie es ausrechnen und starten Sie es mit der material.wdl. Sie werden die vier Kristall-Models sehen. Ich glaube, dass TMW dieses Model erstellt hat, aber da keine Readme Datei dabei war, bin ich nicht allzu sicher. Also, das erste, “normale” Model hat kein Material zugewiesen, das zweite benutzt Conitecs “Smaragd” Material und ich habe noch zwei weitere beigesteuert (“lava” und “marble”).

Sehen Sie sich die Models gut an und drücken Sie dann die “R” Taste (wie “Rotieren) einmal, um fortzufahren:

Sie sehen wieder das “normale” Model (ohne ein Material zu verwenden), eine “shiny” und eine “dark” Version. Ich habe wieder dasselbe Model mit derselben Skin benutzt und alle dramatische Änderungen basieren nur darauf, dass ich verschiedene Materialien verwende. Bereit für mehr? Drücken Sie erneut “R”.

Dieses Mal sehen Sie wieder das “normale” Model und zwei vordefinierte Materialien (“metal” und “unlit”). Wenn Sie nochmals “R” drücken, kommen Sie in unser “Material-Erzeugungs-Labor”:

Hier sollten Sie Ihre Models laden, um das perfekte Material fürm sie zu finden, indem Sie die Parameter auf den Panels anpassen. Klicken Sie auf die Pfeile, um Änderungen zu sehen; einige werden Effekte erzeugen, die nur unter bestimmten Umständen sichtbar sind, aber das sehen wir gleich genauer.

Vielleicht haben Sie das schwarze Model mit dem gelben Kreis in der oberen linken Bildschirmecke bemerkt. Den Kreis habe ich selbst gemalt, um auf das Model hinzuweisen; es ist eine dynamische Lichtquelle, die auf dem Bildschirm bewegt werden kann.

Die meisten der Pfeile, die nutzlos aussahen zeigen ihre Fähigkeiten bei Licht, entweder von der Sonne oder einem anderen dynamsichen Licht. Wie Sie sehen richtet sich die Position der Lichtquelle nicht ganz nach der Mausposition; das ist, weil ich nicht wollte, dass die Lichtentity verlorengeht, weil sie hinter ein Panel oder außerhalb des Bildschirms verschoben wurde.

Also, wie geht das jetzt mit den Materialien? Sie sind nichts weiter als eine Reihe von Parametern, die kontrollieren, inwieweit das Model, Sprite, Terrain oder die Entity Licht reflektiert. Dieses Licht kann aus dem Level kommen oder aber von der Entity selbst erzeugt werden.

Die Einführung ist nun vorbei, nun kommt ein wenig leicht zu verstehender Code. Sehen wir uns zunächst die Panel Definition an:

panel material_pan
{
      bmap = menu_pcx;
      pos_x = 0;
      pos_y = 0;
      layer = 10;

     button = 90, 12, up_pcx, up_pcx, up_pcx, change_material, null, null;
     button = 105, 12, down_pcx, down_pcx, down_pcx, change_material, null, null;
     button = 90, 37, up_pcx, up_pcx, up_pcx, change_material, null, null;
     button = 105, 37, down_pcx, down_pcx, down_pcx, change_material, null, null;
     button = 90, 62, up_pcx, up_pcx, up_pcx, change_material, null, null;
     button = 105, 62, down_pcx, down_pcx, down_pcx, change_material, null, null;

     ...................................

    digits = 125, 12, 3, arial_font, 1, e_red; // emissive_red
    digits = 125, 37, 3, arial_font, 1, e_blue; // emissive_blue
    digits = 125, 63, 3, arial_font, 1, e_green; // emissive_green

    ....................................

    flags = overlay, refresh, visible;
}

Das Panel hat einen Knopf für jeden Pfeil, also haben wir 30 Button- und 15 Digit-Elemente, welche die Werte für jeden Material Parameter anzeigen. Beachten Sie, dass eine einzige Funktion läuft, wenn wir einen Knopf (egal welchen) drücken: change_material().

Die main Funktion ist simpel:

function main()
{
    fps_max = 30;
    sun_light = 1;
    level_load (materials_wmb);
    mouse_map = pointer_pcx;
    mouse_mode = 2;
    while (1)
    {
        mouse_pos.x = pointer.x;
        mouse_pos.y = pointer.y;
        wait (1);
    }
}

Sie limitiert die Frame Rate auf 30 FPS, schaltet Sonnenlicht ein und lädt dann das materials_wmb Level. Wir setzen pointer_pcx als Mauszeiger, zeigen ihn an und erlauben seine Bewegung, indem wir die Koordinaten in einer Schleife anpassen.

Die materials.wdl Datei enthält Definitionen für eine ganze Reihe von Materialien, aber wir werden uns nicht alle ansehen, da sie sehr ähnliche Definitionen haben, lediglich verschiedene Zahlenwerte. Beginnen wir mit dem Lava Material:

material mat_lava
{
     emissive_red = 200;
     emissive_green = 70;
     emissive_blue = 20;
     ambient_red = 255;
     ambient_green = 150;
     ambient_blue = 50;
     diffuse_red = 200;
     diffuse_green = 150;
     diffuse_blue = 50;
     specular_red = 255;
     specular_green = 255;
     specular_blue = 255;
     alpha = 60;
     albedo = 70;
     power = 10;
}

Die ersten drei Parameter regulieren die Stärke und Farbe des Lichtes, das voin der Entity selbst erzeugt wird. Wie Sie sich denken können, ist das “shiny” Material oben entstanden, indem diese “emissive” Parameter auf ihre Maximalwerte gesetzt wurden (255), wohingegen das “dark” Material alle diese Werte auf 0 stehen hat.

Der nächste Satz an Parametern (ambient) reguliert Stärke und Farbe des Lichtes, das die Entity von statischen Lichtern im Level erhält, von ihrem eigenen “ambient” und dem der Kamera. Stellen wir uns vor, Ihr Spiel spielt auf dem Mars und die meisten Objekte, inklusive der Kristalle, sollten rötlich schimmern. Also ist ihre Sonne rot, der Boden ist rot, aber die Kristalle nicht ganz. Mit diesen 3 “ambient” Parametern können Sie ein Material erstellen, das mehr rot von den statischen Lichtquellen im Level erhält; schauen Sie sich an, was ich erhielt, als ich mit den Werten spielte:

Wie Sie sehen benutzt dieses Material keine emissive Parameter, weil es kein Licht erzeugt; es nimmt lediglich mehr rot von den weißen, statischen Lichtquellen an. Natürlich können (und sollten) Sie geeignete “emissive” mit guten “ambient” Werten kombinieren.

Der nächste Parametersatz (diffuse) reguliert den Einfluß dynamischer Lichter (inkl. Sonnenlicht). Machen wir ein Experiment: Starten Sie das Projekt, setzen Sie diffuse_green auf 255 und schauen Sie sich den benutzerdefinierten Kristall an:

Ich konnte keine Änderung feststellen, egal wie genau ich hingesehen habe! Klicken Sie nun auf das schwarze Model (die dynamische Lichtquelle) und ziehen Sie diese näher zum Kristall:

Wie Sie sehen wirft mein weißes dynamisches Licht ein grünes Licht auf das Model; das Material ignoriert die Anteile von rot und blau, weil diffuse_red und diffuse_blue auf 0 stehen. Der letzte Parametersatz (specular) ist ähnlich zu “diffuse”, aber dieses Mal hängt der Effekt vom Winkel der Kamera ab.

Dieses Mal habe ich specular_blue auf 255 gesetzt. Das Ergebnis leuchtet ein: nur ein Teil des Models ist vom dynamsichen Licht betroffen; der große Wert von specular_blue färbt den Kristall blau, aber der Effekt ist nur zu sehen, wenn die Kamera einen bestimmten Winkel hat. Drücken Sie “0” während die Engine läuft und Sie können die Kamera im Level bewegen. Noch etwas: wenn Sie den benutzerdefinierten Kristall anklicken, wird er beginnen / aufhören, um seine z-Achse zu rotieren.

Die letzten 3 Parameter (“power”, “alpha” und “albedo”) sind leicht zu verstehen: sie stellen die Stärke des Effektes ein (0...10), die Durchlässigkeit des Materials (0...100) und den Einfluß des Sonnenlichtes (0...100).

Sie werden sehen, dass einige der Material Definitionen in material.wdl enthalten nicht alle Parameter, da wir manchmal nicht alle brauchen. Ok, wir wissen also jetzt, wie man ein Material definiert. Aber wie benutzt man es?

action test_lava
{
    my.material = mat_lava;
    ..................................
}

Das ist wirklich einfach, nicht wahr? In die Action, die unsere Entity erhalten wird können wir mit einer einzigen Zeile an Code unser vorher definiertes Material einbauen. Die Engine kennt einige vordefinierte Materialien, wie mat_flat, mat_shaded, mat_metal usw. Natürlich können Sie auch deren Werte manipulieren. Hier ist die Action für den “metal” Kristall aus der Demo:

action test_metal
{
    my.metal = on;
    mat_metal.emissive_red = 50;
    mat_metal.emissive_green = 50;
    mat_metal.emissive_blue = 80;
}

Die erste Codezeile setzt das Metal Flag; dadurch wird auch das mat_metal automatisch geladen. Nun kann ich alle Parameter von mat_metal kontrollieren; ich habe es etwas metallischer aussehen lassen, indem ich etwas mehr Licht (insbesondere blaues Licht) hinzugemischt habe. Schauen wir uns die Action für das dynamische Licht an:

action dynamic_light
{
    my.lightrange = 80;
    my.red = 100;
    my.green = 100;
    my.blue = 100;
    my.enable_click = on;
    my.event = move_me;
}

Das Licht hat eine Reichweite von 80 Quants und erzeugt weißes Licht, weil seine RGB Werte alle auf 100 stehen. Die Entity reagiert darauf, angeklickt zu werden; wenn Sie das tun, läuft die move_me Funktion:

function move_me()
{
    while (mouse_left == on)
    {
        temp.x = pointer.x;
        temp.y = pointer.y;
        temp.z = 100;
        vec_for_screen (temp, camera);
        my.x = temp.x;
        my.z = temp.z;
        wait (1);
    }
}

Diese Funktion bewegt die Entity solange die linke Maustaste gedrückt ist. Schauen Sie sich das Bild an, um den Bereich zu sehen, in dem sich die Lichtquelle für temp.z = 100 bewegen kann; ändern Sie den Wert, wenn Sie den Bereich ändern wollen. Die Koordinaten aus temp werden mit vec_for_screen in 3D Koordinaten umgerechnet und die Entity wird auf die neue Position bewegt.

Hier ist der Code für das benutzerdefinierte Model:

action test_user
{
    my.material = mat_user;
    my.enable_click = on;
    my.event = rotate_me;
}

function rotate_me()
{
   rotation += 1;
   while ((rotation % 2) == 1)
   {
       my.pan += 5 * time;
       wait (1);
   }
}

Dieses Model benutzt das mat_user Material, reagiert auf Klicks und startet seine rotate_me Funktion, wenn es mit der linken Maustaste angeklickt wird. Das Model rotiert um seinen pan Winkel solange rotation ungerade ist (also 1, 3, 5, 7, etc.).

Erinnern Sie sich an die große Panel Definition, die am Anfang erwähnt wurde? Jeder Knopf (Pfeil) auf dem Panel startet die gleiche Funktion, wenn er angeklickt wird:

function change_material(button_number)
{
    if (button_number == 1)
    {
        while (mouse_left == 1)
        {
            e_red += 1;
            e_red = min(max(e_red, 0), 255);
            wait (1);
        }
        wait (1);
   }
  if (button_number == 2)
  {
       while (mouse_left == 1)
       {
           e_red -= 1;
           e_red = min(max(e_red, 0), 255);
           wait (1);
       }
       wait (1);
    }

    ......................
}

Die Funktion ist sehr lang, weil alle 30 Knöpfe sie verwenden. Ich habe mich entschieden, nur den Code der ersten zwei Knöpfe zu zeigen, weil der Rest ebenso funktioniert.

Wenn Sie ein regelmäßiger AUM Leser sind, wissen Sie, dass die Funktion change_material eine “1” zurückliefert, wenn der erste Knopf des Panels gedrückt wurde, eine “2”, wenn der zweite gedrückt wurde usw. Die ersten zwei Knöpfe erhöhen bzw. verringern e_red, eine Variable, die den emissive_red Parameter kontrolliert.

Der erste Pfeil erhöht e_red solange die Maustaste gedrückt ist. Die Codezeile:

            e_red = min(max(e_red, 0), 255);

stellt sicher, dass der Bereich 0...255 der Variablen eingehalten wird. Der zweite Knopf verringert den Wert.

Schauen wir uns nun unsere benutzerdefinierte Material Definition an:

material mat_user
{
    emissive_red = 0;
    emissive_green = 0;
    emissive_blue = 0;
    ambient_red = 0;
    ambient_green = 0;
    ambient_blue = 0;
    diffuse_red = 0;
    diffuse_green = 0;
    diffuse_blue = 0;
    specular_red = 0;
    specular_green = 0;
    specular_blue = 0;
    power = 0;
}

All diese mat_user Parameter werden von einer Starter Funktion kontrolliert:

starter set_material()
{
    while (1)
    {
        mat_user.emissive_red = e_red;
        mat_user.emissive_green = e_green;
        mat_user.emissive_blue = e_blue;
        mat_user.ambient_red = a_red;
        mat_user.ambient_green = a_green;
        mat_user.ambient_blue = a_blue;
        mat_user.diffuse_red = d_red;
        mat_user.diffuse_green = d_green;
        mat_user.diffuse_blue = d_blue;
        mat_user.specular_red = s_red;
        mat_user.specular_green = s_green;
        mat_user.specular_blue = s_blue;
        mat_user.power = m_power;
        mat_user.alpha = m_alpha;
        mat_user.albedo = m_albedo;
        wait (1);
    }
}

Die while Schleife aktualisiert die Parameter mit Hilfe der Variablen auf dem Panel. Die letzte Funktion dreht die Kamera um 90 Grad, wenn die “R” Taste gedrückt wird:

function rotate_camera()
{
    camera.pan -= 90;
}

on_r = rotate_camera;

Das ist alles! Ersetzen Sie nun das benutzerdefinierte Model durch ihre eigenen, drücken Sie einige Knöpfe und verblüffen Sie die Welt mit Ihren Materialien!