Das Verwenden von Shadern

Hier ist eine Schritt-für-Schritt-Anleitung, wie man Normalmapping- oder andere Shader an Block-Oberflächen anbringt. Wenn Sie die mit Gamestudio mitgelieferten Standardshader verwenden wollen, benötigen Sie die Version 7.50 Commercial oder höher. 7.50  C 

1. Hinzufügen einer Normal-Map

Eine Normalmap enthält an jeder Pixelposition Informationen über den Oberflächenwinkel und wird in Kombination mit einem Bumpmapping-Shader dazu verwendet, einer Oberfläche einen unebenen Look zu verleihen. Es gibt einige externe Programme zum Erstellen von Normalmaps aus Texturen oder aus Modelldetails.

Endet ein Texturname auf "_n", wird die Textur als Normalmap für eine Basistextur mit demselben Namen verwendet. Wenn Sie also einen Normalmapping-Shader für eine Oberflächentextur namens "stones2" hinzufügen wollen, nehmen Sie eine Normalen-Maptextur, die "stones2_n" heißt. Unten sehen Sie eine typische gekachelte Textur und ihre Normalen-Map:

rock rock_n

In Gamestudios Online-Shop können Sie einen hochauflösenden Ersatz der Standardtexturen inklusive einer WAD-Datei, die Normalmap für sämtliche Oberflächentexturen enthält, kaufen. Um die Normal-Maps ins Level einzufügen, öffnen Sie das Fenster [Presets], klicken auf [Textures], wählen [Add WAD] aus und öffnen dann die im Hochauflösungspaket mitgelieferte hires_nm.wad. Dadurch werden dem Level sämtliche Normalmap von der WAD hinzugefügt.

Alternativ, wenn Sie Texturen aus einem Bilder-Ordner verwenden, kopieren Sie ein Normalen-Map-Bild, das auf "_n" endet, einfach in diesen Ordner (beispielsweise "stones2_n.bmp").  !!  Sorgen Sie dafür, dass die Normalen-Map im Ordner existiert wenn Sie das Level kompilieren und achten Sie darauf, dass ihr Texturname (inklusive "_n" und der Extension) das Limit von 15 Zeichen für Texturnamen in der WMB-Datei nicht überschreitet.

Ausser Normalmaps können Sie Oberflächentexturen ausserdem noch Höhenmaps und Spiegelungsmaps hinzufügen. Eine Höhenmap enthält an jeder Pixelposition Informationen über die Höhe und wird im Alphakanal (Tranparenzkanal) einer Normalmap gespeichert. Von Parallax-Shadern wird sie für Okklusionseffekte benutzt. Eine Spiegelungsmap enthält Helligkeitsinformationen für eine Oberfläche und wird im Alphakanal der Oberflächentextur gespeichert. Sie wird von Spiegel-Bumpmapping-Shadern verwendet.

2. Hinzufügen eines Material-Skripts

Eine Normalen-Map alleine genügt nicht - Sie werden ausserdem ein Material mit einem Normalmapping-Shader an der Leveloberfläche, an der der Effekt auftauchen soll, anbringen müssen. Materialien befinden sich in einem Skript. Die mit Gamestudio mitgelieferten vordefinierten Shader sind im Skript mtlFX.c, das sich in jedes Mainskript eines Levels einbinden läßt, enthalten. Hat Ihr Level bereits ein .c-Skript (.wdl geht nicht), sorgen Sie einfach dafür, daß dieses Skript die Zeile #include "mtlFX.c". enthält. Hat Ihr Level noch kein Skript, erstellen Sie eines: wählen Sie File/Map Properties, klicken Sie auf das Icon [New] neben dem Script-Feld und gehen Sie auf A7_lite_C_project. Dadurch wird automatisch ein Skript erstellt und die mtlFX.c-Shaderkollektion mit eingefügt.

3. Anbringen des Materials

Nachdem Sie das Skript hinzugefügt haben, markieren Sie Block oder Gruppe, den bzw. die Sie an den Shader anbringen wollen und klicken im Eigenschafts-Panel auf das Icon [Choose] neben dem Material-Feld. Sie bekommen daraufhin eine Kollektion an Materialien aus der Sie auswählen können. Fürs Normalen-Mapping wählen Sie z.B. mtl_bump oder mtl_specBump. Je nach Einstellung von d3d_automaterial im Skript, wird das Material auch automatisch allen Blocks mit derselben Textur zugewiesen.

4. Platzieren eines dynamischen Lichts

Das dritte Element, welches Sie zum Normalen-Mapping brauchen ist eines oder mehrere Lichter. Wählen Sie File / Map Properties und sorgen Sie dafür, dass Sun-Licht aktiviert istl. Oder Sie platzieren gleich neben die vom Normalen-Mapping betroffene Oberfläche eine Lichtquelle. Sorgen Sie dafür, dass die Oberfläche innerhalb der Reichweite des Lichts liegt und das [Dynamic]-Flag der Lichtquelle mit einem Haken versehen ist ((A7.60 oder höher). Oder aber, Sie setzen ein dynamisches Licht ins Skript. Dies geschieht mit einer lite-C-Funktion wie dieser:

function light_place(x,y,z,r,g,b,range)
{ 
  ENTITY* light = ent_create(NULL,vector(x,y,z),NULL);
  light.red = r;
  light.green = g;
  light.blue = b;
  light.lightrange = range;
}


function main()
{
  ...
  level_load(...);
  light_place(100,100,100,0,0,255,1000);
  ...
}

Ausser auf dynamische Lichter, können Blockoberflächen auch auf Sonnenlicht reagieren. Die läßt sich über den albedo-Wert des zugewiesenen Shadermaterials einstellen.

5. Staunen Sie über das Resultat

Kompillieren Sie das Level per Build, klicken Sie dann auf auf der Werkzeugleiste auf das Icon [Run] neben dem [Build]-Knopf. Mit Pfeiltasten oder Maus navigieren Sie sich nun zu dem Block an dem Sie den Shader angebracht haben. Läßt der Shadereffekt sich mit den Entity-Skills, wie etwa skill41..skill44 für vordefinierter Shader, anpassen, setzen Sie die Skills nach Laden des Levels global auf den Entity-Pointer level_ent. Und wenn das Resultat nicht einfach nur dermassen gut aussieht, lesen Sie weiter ...

6. Anpassen des Lichts

Sobald sich Blocks Ihres Levels im Bereich von mehr dynamischen Lichtern befinden, als Ihr Shader das unterstützt, kan das Sortieren der Lichter Artifakte verursachen. Die geschieht, aufgrund der unterschiedlichen Abstände der Blockzentren zu den Lichtquellen dann, wenn der Licht-Manager verschiedene Sets von Lichtern benachbarten Blocks zuweist. Das Ergebnis können, wie Sie im Screenshot unten nahe der rechten Wand sehen können, scharfe Helligkeitsunterschiede entlang der Blockgrenzen sein:

Es gibt drei mögliche Wege, solche Lichtartifakte zu vermeiden:

Die letzte Methode ist die beste, denn sie verbessert sowohl die Framerate als auch den Look des Levels. Nehmen Sie zum Einstellen der Reichweiten der Lichter den Shader mtl_lightcount. Der Shader zeigt die Anzahl der Lichter in Reichweite des View-Frustums an und ein Block-Mesh im Farbcode: schwarz = 0, grau = 1, blau = 2, grün = 3, zyan = 4, rot = 5, magenta = 6, gelb = 7, weiß = 8 oder mehr. Passen Sie die dynamischen Lichter solange an, bis kein Bereich Ihres Levels einen höheren Farbcode als blau oder grün hat. Unten sehen Sie das Bild des obigen Levels mit viel zu vielen dynamischen Lichtern:

The last method is the best because it also improves the frame rate and the look of the level. Use the mtl_lightcount shader for adjusting light ranges. The shader displays the number of lights in range of the view frustum and a block mesh in color code: black = 0, grey = 1, blue = 2, green = 3, cyan = 4, red = 5, magenta = 6, yellow = 7, white = 8 or more. Adjust dynamic lights until no area of the level has a higher color code than blue or green. Below you'll see the image of the level above with way too many dynamic lights:

Um vorübergehend sämtliche vordefinierten Shader durch den Lichtzählshader zu ersetzen, kopieren Sie mtlFX.c in Ihren Work-Ordner, editieren Sie die Materialdefinition und esetzen Sie vorübergehend die ursprüngliche Zeile effect = "....fx"; duch effect = "lightcount.fx";.► latest version online