Surface mit geglätteten Kanten

  • Allgemein

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • Surface mit geglätteten Kanten

    Halli-Hallöchen liebe Gm-D Community,

    nach drei Jahren bin ich wieder hier aktive, nachdem ich GameMaker-Studio doch tatsächlich bei Steam entdeckt habe. Leider bin ich etwas eingerostet und muss erstmal meine alten Hirnzellen aus den Kühlfach hohlen die mein gesamtes GML-Wissen beinhalten.

    Der Stand der Dinge:
    Ich habe ein Charakter, der aus einzelnen Sprites besteht (Körper, Arme, Kopf...), damit ich diese einzel animieren kann. Das klappt im Draw-Event auch super, aber ich habe vor auf diesen Charakter 'pseudo Shader' anzuwenden, sprich mal ist er fast durchsichtig, Farben werden negiert, Schatten, usw. Darum wollte ich diesen in ein Surface im Step-Event zeichnen.

    Das Problem:
    Die Sprites sind an den Kanten geglättet, sprich der Alpha wert nimmt ab. Zeichne ich jetzt zwei Sprites übereinander, so gibt es hässliche Kanten:

    Achtet auf die weißen Linien übern den Beinen. Das Bild ist an dieser Stelle Transparent und zeigt lediglich den Hintergrund.

    Warum passiert das:
    Der GameMaker legt die Bilder übereinander, indem er Pixel für Pixel des Surfaces mit den überlappenden Bild ersetzt. Allerdings wird auch der Alpha-Wert ersetzt, auch wenn der neue Wert wesentlich kleiner ist als der alte. So ist die Unterlage auf 100% Alpha und das überlappende Bild an dieser Stelle nur 10%, weil es zum Beispiel eine Kante ist. Jetzt ist das Surface selbst an dieser Stelle auch auf 10% Alpha, statt diesen Wert zu 'addieren' und auf 100% Alpha zu bleiben.

    Der Hauptlayer (im Draw-Event) besitzt kein Alpha-Kanal und jeder Pixel hat eine 100%tigen Alpha-Wert, darum klappt es ohne Surface problemlos. Den Alpha Kanal brauch ich aber, da ein schwarzer Kasten um den Spieler ziemlich witzlos ist.

    Was ist die Lösung?
    Man muss sicher den BlendMode einstellen, so dass er Farben ersetzt (bm_normal), aber den Alpha wert addiert, oder zumindest immer das Maximum nimmt. Leider hab ich damit nicht wirklich Erfahrung und stumpfsinniges herumprobieren bringt mich nicht zum Ziel. Hier im Forum und in der GMC hab ich nur Lösungen gefunden, die ein Problem mit draw_set_alpha() betreffen, diese haben leider nicht funktioniert.

    Die Bilder haben wirklich an den Ecken einen Alpha-Wert und sind auch richtig importiert. Das ist ja seit GM-8 auch endlich möglich.
    Ich benutze Studio Pro mit dem Windows-Exporter.

    Neulich im Step-Event:
    Spoiler anzeigen

    GML-Quellcode

    1. // Auf surface zeichnen
    2. surface_set_target(surface);
    3. // Hintergrund leeren
    4. draw_clear_alpha(c_black, 0);
    5. // Hinteren Fuß
    6. draw_sprite_ext(sprFeedL, 0, feedX, feedY, 1, 1, bodyRot + feedLRot, c_white, 1);
    7. // Hinteren Arm
    8. draw_sprite_ext(sprHandL, 0, handX, handY, 1, 1, bodyRot + handLRot, c_white, 1);
    9. // Körper
    10. draw_sprite_ext(sprBody, 0, bodyX, bodyY, 1, 1, bodyRot, c_white, 1);
    11. // Kopf
    12. if (eyeClose < 0)
    13. draw_sprite_ext(sprHeadEyeClose, 0, headX, headY, 1, 1, bodyRot + headRot, c_white, 1);
    14. else
    15. draw_sprite_ext(sprHead, 0, headX, headY, 1, 1, bodyRot + headRot, c_white, 1);
    16. // Vordere Hand
    17. draw_sprite_ext(sprHandR, 0, handX, handY, 1, 1, bodyRot + handRRot, c_white, 1);
    18. // Vorderen Fuß
    19. draw_sprite_ext(sprFeedR, 0, feedX, feedY, 1, 1, bodyRot + feedRRot, c_white, 1);
    20. surface_reset_target();
    Alles anzeigen

    *Ich zeig ganz bewusst nur die Füße, weil das Gesicht momentan so hässlich aussieht, dass der Spieler absichtlich sterben würde um den Charakter zu erlösen.
    „Zwei Dinge sind unendlich, das Universum und die menschliche Dummheit, aber bei dem Universum bin ich mir noch nicht ganz sicher.“
    Albert Einstein
  • Eine genaue Erklärung deines Problems und eine Lösung dafür findest du in diesem Thread.

    Dein "Warum passiert das" stimmt also nicht ganz, wie du in obigem Thread nachlesen kannst. Der Alpha-Wert wird nicht einfach nur ersetzt, sondern berechnet sich zu , wobei den Alpha-Wert des zu zeichnenden Pixels darstellt und den des Pixels, auf den gezeichnet wird. Wenn also wie in deinem Fall gerade 1 ist, dann ist der resultierende Alpha-Wert nur dann 1, wenn entweder 0 oder 1 ist. Zeichnet man also halbtransparente Pixel wie bei den Kanten deiner Sprites, dann entsteht dieser "Fehler". In obigem Thread findest du eine Lösung des Problems.
  • Vielen Dank für deine Antwort,

    ich hab die Anleitung mal befolgt und es sieht tatsächlich besser aus.

    Aber irgendwie sieht der Übergang am Arm und an den Beinen seltsam aus (siehe Bild).
    Selbst wenn ich die Glättung mit Schwarz, 0%-Alpha ersetze ist der Bereich leider immer noch seltsam.
    „Zwei Dinge sind unendlich, das Universum und die menschliche Dummheit, aber bei dem Universum bin ich mir noch nicht ganz sicher.“
    Albert Einstein
  • Ich muss zugeben, als ich schon mal vor dem selben Problem stand und ich das Tool von Tobi97 benutzen wollte, hat es mit der umgewandelten Grafik irgendwie auch nicht funktioniert. Ich hatte es damals dann irgendwie anders gemacht, aber von der Theorie her müsste es ja funktionieren. Wenn es dir nichts ausmacht, kannst du ja mal die betreffenden Ausgangsgrafiken (oder ähnliche) hochladen, damit wir uns das mal selber anschauen können.
  • Jow kann ich machen,

    mir ist außerdem aufgefallen, dass im Originalbild des Bein's die Farbe an der Kante immer die selbe ist und lediglich der Alphawert abnimmt, während im vor-multipliziertem Bild die Farbe mit abnehmenden Alphawert immer dunkler wird. Soweit wie ich das verstanden habe ist das ja auch der Sinn des Tools, nur irgendwie ergibt das bei dieser Kante keinen Sinn.

    Im Anhang sind die Grafiken. Bitte nicht stibitzen.
    gfx_src: original Bilder
    gfx: vor-multiplizierte Bilder
    Dateien
    • sprNinja.rar

      (92,93 kB, 134 mal heruntergeladen, zuletzt: )
    „Zwei Dinge sind unendlich, das Universum und die menschliche Dummheit, aber bei dem Universum bin ich mir noch nicht ganz sicher.“
    Albert Einstein

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von dave ()

  • Ich hab dir mal schnell was gebaut. Wie schon angedeutet, muss es irgendein Problem mit dem Tool aus dem Tutorial geben, da ich mit deinen umgewandelten Grafiken zum gleichen Fehler komme. In dem Projekt im Anhang habe ich deshalb deine Originalgrafiken verwendet und sie zu Beginn mit einem Script umgerechnet. Schau's dir mal an.
    Dateien
    • test.rar

      (13,45 kB, 154 mal heruntergeladen, zuletzt: )
  • Irgendwas bringt die Studio Version da wieder was durcheinander ... ich sehe nur eine weiß Fläche.

    Der Inhalt des Surfaces wird mit den Aufruf von premultiply_surface gelöscht.
    Genauer gesagt beim Zeichnen der Kopie:

    GML-Quellcode

    1. // Multiply with alpha of temporary surface.
    2. draw_set_blend_mode_ext(bm_zero,bm_src_alpha);
    3. draw_surface(tmp,0,0);

    Yoyogames hat auch an den Surfaces rum geschraubt, so darf man diese auch nur noch im Draw-Event zeichnen. Andernfalls aktiviert man den geheimen 'SunnyTown-Modus'.
    Aber selbst das macht hier leider keinen Unterschied.
    Sieht es bei dir den richtig aus?
    „Zwei Dinge sind unendlich, das Universum und die menschliche Dummheit, aber bei dem Universum bin ich mir noch nicht ganz sicher.“
    Albert Einstein
  • Eigentlich hätte ich noch den GM7, aber ich müsste den erst über *schluck* Softwrap reaktivieren, falls es überhaupt noch möglich ist (womit ich nicht sagen will, dass es jemals mit gesunden Menschenverstand möglich gewesen wäre). Außerdem unterstützte der SpriteEditor von damals keine halbtransparent.
    Vielleicht entstehen die Ungenauigkeiten beim Speichern des Surfaces als Datei, was jedoch nicht erklärt warum die Studio-Version das komplette Surface löscht, bzw. auf 100% Transparenz setzt. Interessanterweise funktioniert das InGame-Vormultiplizieren auf mein Android perfekt, dort hatte ich vorher mit den Tool genau die selben Probleme. :huh:
    „Zwei Dinge sind unendlich, das Universum und die menschliche Dummheit, aber bei dem Universum bin ich mir noch nicht ganz sicher.“
    Albert Einstein
  • Schade. Da ich das Studio nicht habe, kann ich es leider nicht testen und die genaue Ursache herausfinden. Sonst hätte ich mir das gerne mal angeschaut. Eventuell gibt es einen Workaround oder es liegt tatsächlich ein Bug vor, den man melden könnte.

    Kann mir zwar kaum vorstellen, dass es daran liegt, aber probier doch mal statt

    GML-Quellcode

    1. draw_set_blend_mode(bm_add);

    im Script premultiply_surface den Blend Mode

    GML-Quellcode

    1. draw_set_blend_mode_ext(bm_one,bm_one);

    Sind die Alpha-Werte nämlich nicht gerade 1, dann verhalten sich diese Blend Modes verschieden. Ist jetzt einfach mal geraten. Eventuell wurden ja Blend Modes in der Studio Version leicht geändert.
  • Okey, das Problem liegt an surface_copy. Hab sowohl Ziel als auch Quelle nach den Aufruf von surface_copy zeichnen lassen und das Ziel bleibt einfach leer. Wenn ich das Surface einfach zweimal erstelle, statt es zu kopieren funktioniert es wie gewollt.

    Ich hab jetzt eine andere Lösung gefunden, indem ich alles in ein Surface überblende:

    GML-Quellcode

    1. // argument0: ID of sprite// argument1: Index of subimage
    2. var w, h, tmp;
    3. w = sprite_get_width(argument0);h = sprite_get_height(argument0);
    4. // Temporary surface used to preserve alpha information.tmp = surface_create(w,h);
    5. // Clear alpha channel to 1.surface_set_target(tmp);draw_clear_alpha(c_black,0);draw_set_blend_mode_ext(bm_one,bm_zero);draw_sprite(argument0,argument1,0,0);draw_set_blend_mode_ext(bm_one,bm_one);draw_set_color(c_black);draw_set_alpha(1);draw_rectangle(0,0,w,h,false);
    6. // Multiply with alpha of temporary surface.draw_set_blend_mode_ext(bm_zero,bm_src_alpha);draw_sprite(argument0,argument1,0,0);draw_set_blend_mode(bm_normal);
    7. surface_reset_target();
    8. return tmp;


    Edit: Tut mir leid, der verschluckt beim Posten die Leerzeilen, irgendwie läuft der GML-Tag Amok.


    Das funktioniert nun endlich wie gewollt. Man sollte den linieren Pixel-Verlauf für das Erstellen der Surface deaktivieren, so dass dies nur noch für das Zeichnen des endgültigen Surfaces auf die Hauptfläche aktive ist. Ansonsten ist das Bild sehr unscharf, da die Kanten 3 mal geglättet werden.

    GML-Quellcode

    1. texture_set_interpolation(false);
    „Zwei Dinge sind unendlich, das Universum und die menschliche Dummheit, aber bei dem Universum bin ich mir noch nicht ganz sicher.“
    Albert Einstein

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von dave ()