Shader Tutorial I

      Shader Tutorial I

      Hallo Leute,

      ich habe mich ein wenig an Shader rumgespielt und mir fällt ein, das der Sprache recht ähnlich mit anderen Sprachen wie C#, Java etc. sind. Eigentlich ist Shader doch recht einfacher als C#/Java, da man nur die Farbe manipuliert kann.
      In dieser Tutorials werde ich euch ein wenig über Shader zeigen, wie man ihn benutzt, was es bedeutet, etc. Ich werde es so simpel wies möglich versuchen zu erklären, damit jeder von euch auch gut versteht.

      Ihr sollte natürlich vorher bei Shader Basic von @LEWA anschauen, den hier wird nicht so viel über Funktionen besprochen. Hier ist ja nur eine Tutorial, wie man Shader benutzen kann.

      Dieser Tutorial ist eher an Fortgeschrittene GML-Erfahrung gedacht, die schon ein wenig Erfahrung beim Programmieren haben. ;)

      Wir fangen erstmal an, wie wir zum Beispiel weiße Pixel in blaue Pixel von Sprite umwandeln können.

      Als Beispiel-Sprite nehmen wir dies: (jaja, ich bin ein Pixel-Artist-Profi)



      Den fügt ihr erstmal als Sprite in Game Maker ein.
      Jetzt erstellen wir eine Objekt "obj_blauesKopf" und wir schreiben das in Draw Event:

      GML-Quellcode

      1. shader_set(sh_whiteToBlue); //Shader Funktion wird aktiviert
      2. draw_self();
      3. shader_reset(); //Shader Funktion ignorieren

      Fügt das Objekt in Room ein, jetzt können wir vorerst Objekt ignorieren. Wir erstellen dazu jetzt eine neue Shader und wir nennen sie "sh_whiteToBlue" um.
      Wenn ihr dieser Shader jetzt öffnet, seht ihr "Vertex" und "Fragment" bei Tab. Wir ignorieren vorerst "Vertex", den brauchen wir jetzt noch nicht. Wir gehen also zu "Fragment". Da können wir unsere Farbe-Pixel manipulieren.

      bei Fragment sollte euch bei euch so aussehen:

      GML-Quellcode

      1. //
      2. // Simple passthrough fragment shader
      3. //
      4. varying vec2 v_vTexcoord;
      5. varying vec4 v_vColour;
      6. void main()
      7. {
      8. gl_FragColor = v_vColour * texture2D( gm_BaseTexture, v_vTexcoord );
      9. }


      So, bei der "void main()"-Codeabschnitt wird bei jede einzelne Pixel von Sprite ausgeführt und natürlich kriegen wir auch jede einzelne Pixel von Sprite die Farbwerte.

      Jetzt erkläre ich ein wenig, was "float, vec2, vec3 und vec4" bedeutet:

      float -> Das ist eine Typ, welches Zahlen inklusiv Kommastellen benutzen kann. In Game Maker kennen wir als "real". Allerdings muss man bei float immer so eine Format haben: 1.0, 124.9, 300.0
      vec2 -> Das ist eine Typ, welches 2x Zahlen darauf nutzen kann. Dieser beide Zahlen sind wiederum auch float. Als kleiner Beispiel (verlgleich mit Game Maker):

      GML-Quellcode

      1. Position = vec2(obj_player.x,obj_player.y); //in Shader
      2. PositionX = obj_player.x; //in Game Maker
      3. PositionY = obj_player.y;


      Vorteil bei vec2 -> es werden weniger Variable verbraucht und man kann besser einordnen.

      vec3 -> Das ist wie vec2, nur man kann 3 werte statt 2 werte benutzen. Als Beispiel:

      GML-Quellcode

      1. Farbe = vec3(rot, grün, blau); //in Shader
      2. FarbeRot = rot; //in Game Maker
      3. FarbeGrün = grün;
      4. FarbeBlau = blau;


      oder

      GML-Quellcode

      1. Position = vec3(x,y,z); //in Shader
      2. PositionX = x; //in Game Maker
      3. PositionY = y;
      4. PositionZ = z;


      vec4 -> siehe oben, man kann 4 werte statt 3 werte gleichzeitig benutzen.

      gl_FragColor ist eine vec4-Typ. Das heißt, das 4 werte da drin sich befindet, nähmlich Rot, Blau, Grün und Alpha.
      Und dadrin befindet sich die Farbwert von Sprite (eigentlich befindet sich die Farbwerte von Sprite in Texture2D)

      Wir können die Werte auch einzeln aufrufen, indem wir zum Beispiel:

      GML-Quellcode

      1. varying vec2 v_vTexcoord;
      2. varying vec4 v_vColour;
      3. void main()
      4. {
      5. gl_FragColor = v_vColour * texture2D( gm_BaseTexture, v_vTexcoord );
      6. float roteWert = gl_FragColor.r; //Wir haben jetzt den rote Wert von Sprite in Variable "roteWert". Beachte -> float ist wie real in Game Maker.
      7. float blaueWert = gl_FragColor.b; //Wir haben jetzt den blaueWert von Sprite in Variable "blaueWert".
      8. float grüneWert = gl_FragColor.g; //Wir haben jetzt den grüne Wert von Sprite in Variable "grüneWert".
      9. }


      Wenn wir nur rote Pixel haben, dann sehen die gewöhnlich so aus:
      Red = 255;
      Green = 0;
      Blue = 0;

      Bei Shader würde allerdings so aussehen:
      Red = 1.0;
      Green = 0.0;
      Blue = 0.0;

      Wenn es nur halb Rot ist, dann würde es bei normaler Farbwerte so aussehen:
      Red = 128;
      Green = 0;
      Blue = 0;

      bei Shader:

      Red = 0.5;
      Green = 0.0;
      Blue = 0.0;

      Bei Shader gibt die Farbwerte nur 0 bis 1 raus.

      So genug geplaudert. Jetzt wollen wir zum beispiel Weiße Pixel in Blaue Pixel umwandeln. Weiße Pixel beihaltet ja die Farbwert (Rot = 1, Grün = 1; Blau = 1) und die Blaue Pixel (Rot = 0; Grün = 0; Blau = 1).
      Also schreiben wir folgendes in Shader herein:


      GML-Quellcode

      1. varying vec2 v_vTexcoord;
      2. varying vec4 v_vColour;
      3. void main()
      4. {
      5. gl_FragColor = v_vColour * texture2D( gm_BaseTexture, v_vTexcoord );
      6. if (gl_FragColor.r == 1.0 && gl_FragColor.g == 1.0 && gl_FragColor == 1.0){ //der Pixel ist weiß!
      7. gl_FragColor.r = 0.0; // r = Rot
      8. gl_FragColor.g = 0.0; // g = Grün
      9. gl_FragColor.b = 1.0; // b = Blau
      10. //setze weiße Pixel in blaue Pixel
      11. //Alternativ können wir auch so machen:
      12. //gl_FragColor = vec4(0.0,0.0,1.0, 1.0);
      13. //das ist eine vec4-Typ und darauf könnt ihr rot, grün, blau und alpha werte nutzen.
      14. }
      15. }


      Wenn wir das Spiel starten, sehen wir dann eine blaues Gesicht, welches in Weiß war:


      So, ihr habt es geschafft! Oder wollt ihr etwa eine grünes Gesicht haben? Dann müsst ihr die Wert blau auf 0.0 setzen und die grüne wert auf 1.0 setzen.

      ---

      Ich weiß, meine Deutsch ist gerade nicht der beste für dieser Tutorials. Aber wenn einer mal Lust hat, dieser Tutorial zu korrigieren, dann würde ich mich sehr freuen. ^^
      Wenn es euch gut gefallen hat, dann mache ich gern eine weitere Shader-Tutorial.


      //Edit: ein wenig korrigiert.
      Ihr stinkt.

      Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „Chinafreak“ ()

      Ich würde mich über evtl ein, zwei Anwendungsbeispiele in Spielen freuen.

      Der Code wurde eigentlich recht gut erklärt - ich für meinen Teil hab es verstanden. Aber ich sehe im Moment grad noch keinen nutzen die Farbe im Spiel zu ändern, wenn ich doch gleich ein blaues Gesicht hätte nutzen können :)

      Ist früh am morgen, aber falls einer paar Anwendungsbeispiele (inklusive Code) posten kann wäre das sicherlich für einige hilfreich ;)
      @mirko2002 natürlich werde ich es machen. Wie gesagt, in dieser Tutorial geht es darum, wie genau man die Farbwerte manipulieren kann. Am Ende werde ich eventuell eine Tutorial machen, wie ich das hier gemacht habe:



      Erstmal sind Anfang wichtiger, das es einfach ist + auch zum verstehen ist.
      Eine weitere Tutorials mache ich gern nächste Woche.
      Ihr stinkt.
      Hallo. Ganz nett, und da ich jetzt ja stolzer Besitzer von Studio bin, muss ich mich ja mit Shaders beschäftigen :)
      Eine Frage hätte ich aber. Woher weiß gm, dass der Pixel den Farbwert von gl_FragColor bekommt. Du gibts diesen Wert ja nirgends zurück, bzw. es wird ja nirgends deklariert. Muss die Variable immer so heißen? Bzw. ist diese einfach fix vorgeben? Kann ich diese Variable wie in Java als Klassenvariable sehen? Kanns jetzt leider selbst nicht ausprobieren, aber will mich in das Thema mal reinlesen.

      LG
      Rodrog
      Je mehr Käse, desto mehr Löcher.
      Je mehr Löcher, desto weniger Käse.
      Ergo: Je mehr Käse, desto weniger Käse.
      gl_FragColor ist eine globale Variable. Sie muss immer gesetzt werden im Fragment Shader, genauso wie gl_Position im Fragment Shader. Es ist sozusagen der finale Wert nach dem überhaupt gesucht wird. Wo sich jetzt dieser Pixel befindet entscheidet der Rasterizer, welcher feste Hardware in der Grafikkarte ist. Für die einzige Orientierung, was das für ein Pixel ist, gibt es die varyings. Dieser Wert wird dann, entsprechend des Blend Modes, mit dem darunter liegenden Pixel verrechnet und dann gezeichnet. Mithilfe des Schlüsselwortes discard kann man auch den zu zeichnenden Pixel komplett ignorieren. Damit funktionieren die meisten Masken in 3D (z.B Maschendrahtzaun) und sind die einfachste und schnellste Möglichkeit für Transparenz.

      GML-Quellcode

      1. gl_FragColor = v_vColour * texture2D( gm_BaseTexture, v_vTexcoord );


      gl_FragColor ist bloß nur ein Variable, der dann als Ausgabe die Farbpixel von Monitor rausbringt, wie Chris987 es gerade eben gesagt hat. Der wahre pixelfarbwert von sprite ist in texture2D(gm_BaseTexture, v_vTexcoord);

      gm_BaseTexture -> Texture Pages (eine Beispiel aus meiner alter Projekt)
      v_vTexcoord -> der jetzige Position von Pixel (in Bereich unsere Sprite) in Texture Pages (auch da sind die Koordinaten von 0 bis 1)
      Ihr stinkt.

      Chinafreak schrieb:

      @mirko2002 natürlich werde ich es machen. Wie gesagt, in dieser Tutorial geht es darum, wie genau man die Farbwerte manipulieren kann. Am Ende werde ich eventuell eine Tutorial machen, wie ich das hier gemacht habe:



      Erstmal sind Anfang wichtiger, das es einfach ist + auch zum verstehen ist.
      Eine weitere Tutorials mache ich gern nächste Woche.

      Hallo, könnt Ihr mir schreiben, wie dieser effekt heißt?
      ich bin ja kein Experte, aber ich glaube das ist einfach mit If abfragen und macht evtl. die Alpha auf 0. Kann natürlich anders ablaufen, aber ich schätze mal, dass das so geht.
      Ein Bug ist mehr als nur ein Bug, es ist ein... Käfer!
      Egal, wie gut du eine Mauer baust, sie fällt um.... der klügere gibt nach :D

      Willst du mit mir auf Discord Chatten/Quatschen?
      Meine Husi's Tutorial Reihe
      mit foreground culling(3D) oder cutout vignette[2D] findest du ähnliches zu dem thema aber eher allgemein gehalten, wissenschaftliche arbeiten zu programmieren etc, also sehr trocken^^

      Dieser Effekt lässt sich aber nciht nur mit Shadern erschaffen, sondern wurde vor allem vor Studio zeiten mit Surfaces gemacht, dann zieht er mit Hilfe einer schwarz-weiß maske den sichtbereich vom Busch ab und es entsteht ein Loch im busch. Klingt komplizierter als es ist. Google einfach "gamemaker surface" da findest du tutorials und den offizielen leitfaden. :)

      ancient-pixel.com
      youtube.com/user/SebastianMerkl <<< ich freu mich über einen Besuch ;)
      Ja schon, aber mit Shader oder Surface bist du besser dran,

      du kannst eine zweite view benutzen und dann im draw event folgende abfrage einsetzen

      GML-Quellcode

      1. if view_current != 2
      2. {
      3. //draw nur wenn du in view 1 bist
      4. }


      aber damit wird nichts abgeschnitten oder auch kein Loch hineingemacht, sondern das gesamt Sprite wird nicht gedrawed.

      ancient-pixel.com
      youtube.com/user/SebastianMerkl <<< ich freu mich über einen Besuch ;)
      Nachdem ich mich vor kurzem mit genau der gleichen Frage auseinandergesetzt habe:

      Nein, also nicht direkt. Man kann nur RGB-Werte manipulieren.
      Wenn du HSV-Werte willst musst du RGB zuerst in HSV konvertieren.

      Habe es selber noch nicht ganz verstanden (daher noch nicht implementiert),
      aber wenn du es per Copy and Paste haben willst, gibt es hier eine Methode.
      (unten bei den Antworten)
      @Chinafreak

      hy tolles tütorial..

      aber ich hab ein problem....also es fünktioniert aber wenn ich nür das nehme

      GML-Quellcode

      1. ​gl_FragColor = vec4(0.0,0.0,1.0, 1.0);


      dann wird das sprite komplett mit grün übermalt in einer vierreck form...wieso?..

      achja ünd wann kommt das nächste??
      Wie gesagt, gl_FragColor enthält 4 Wert, die auf vec4 gespeichert sind.
      Dieser 4 Werte sind für Rot, Grün, Blau und Alpha (aka Transparent). Deine Code machst du so, das die transparente Stelle wieder sichtbar machst.

      gl_FragColor = vec4(0.0,0.0,1.0, 1.0);

      Da wo Rot markiert ist, ist für transparent zuständig. ;)

      Die Nächste wird nicht mehr kommen, da ich nicht mehr aktiv Game Maker benutze.
      Ihr stinkt.