Ergebnis 1 bis 16 von 16

Thema: GLSL Fragment Shader: Palette Swapping

  1. #1

    GLSL Fragment Shader: Palette Swapping

    Guten Tag.
    Ich habe mich vor kurzem mit GLSL Fragment und Vertex Shadern auseinandergesetzt.
    Ich bin nun also dabei einen eigenen Fragment Shader zu schreiben um schnelles und effektives Palette Swapping in meiner OpenGL-Anwendung umsetzen zu können.
    Dabei handelt es sich jedoch nicht nur um simples Palette Swapping sondern mit einer kleinen Feinheit dabei: Ich will nämlich bestimmte Bereiche des Sprites voneinander trennen und eigenständigen Paletten zuordnen.
    Zum Beispiel Haut, Haar und Kleidungspaletten.
    Ich habe mir also gedacht die Pixel in der Sprite-Textur dazu zu verwenden Informationen zu verschlüsseln.
    Der grüne Farbwert gibt an welchen Index der Pixel in der Palette haben soll, der rote Farbwert gibt an um welchen Typ (Haut, Haar, Kleidung) es sich handelt. Der blaue wird (noch) nicht verwendet und Alpha wird einfach übernommen.

    Nun habe ich einen ersten naiven Ansatz für den Shader geschrieben (Im Moment noch ohne die Typen) und ihn auch erfolgreich kompilieren können:
    Code:
    // texture
    uniform sampler2D tex;
    
    // id of palette to be used
    uniform int palette = 0;
    
    // the offset for each type in a single palette, 0 - 10 => body, 11 - 14 => skin, 15 - ... => hair
    uniform int offset_array[3] = {0, 11, 15};
    
    // the palette
    uniform vec3 color_table[30] = {
        vec3(0, 0, 1), vec3(1, 0, 0), vec3(1, 0, 0), 
        vec3(1, 0, 0), vec3(1, 0, 0), vec3(1, 0, 0),
        vec3(1, 0, 0), vec3(1, 0, 0), vec3(1, 0, 0), 
        vec3(1, 0, 0), vec3(1, 0, 0),vec3(1, 0, 0), 
        vec3(1, 0, 0), vec3(1, 0, 0), vec3(1, 0, 0),
        vec3(1, 0, 0), vec3(32, 72, 49), vec3(72, 128, 126), 
        vec3(152, 192, 185), vec3(72, 232, 83), vec3(96, 248, 164), 
        vec3(248, 248, 248), vec3(66, 152, 56), vec3(56, 64, 144), 
        vec3(32, 42, 90), vec3(131, 120, 232), vec3(24, 24, 24), 
        vec3(82, 54, 32), vec3(172, 110, 76), vec3(204, 148, 96)
    };
    
    void main(){
        vec4 color = texture2D(tex, gl_TexCoord[0].st);
    
        // the red value of a fragment determines the type: body, skin, hair
        int type = int(color.r * 255);
    
        // the green value of a fragment determines the index in the palette
        int index = int(color.g * 255);
    
        // the type determines the offset in the palette
        int offset = offset_array[type];
    
        // the color is picked from the palette according to offset, index and palette id.
        vec3 final_color = color_table[int(offset + index + palette * 15)];
    
        gl_FragColor = vec4(final_color.r, final_color.g, final_color.b, color.a);
    }
    Und ich könnte auch damit weiterarbeiten und den Shader vervollständigen wenn da nicht ein kleines Problem wäre:
    Die Daten welche "gl_TexCoord[0].st" liefert sind alle zwischen 0.0 und 1.0 angesiedelt und nicht die reinen Byte-Daten.
    Das öffnet natürlich Tür und Tor für Rundungsfehler und macht dadurch das gesamte System kaputt.

    Gibt es also einen Weg auf die RGBA-Werte eines Fragments direkt in Byte-Form zugreifen zu können?
    Und gibt es vielleicht einen Vorschlag für eine bessere Methode dieses Ziel zu erreichen?

    Vielen Dank für die Hilfe.

    Geändert von Cornix (19.01.2013 um 13:13 Uhr)

  2. #2
    Was genau willst du? Die genau Pixelposition? Dann kannstdu doch die Texturkoordinate einfach mit den Breite/Höhe der Textur in Pixel multiplizieren oder? Dann hast du immer genau das fragment das bearbeitet wird.

  3. #3
    Die Zeile:
    Code:
    vec4 color = texture2D(tex, gl_TexCoord[0].st);
    Gibt mir bereits einen 4-dimensionalen Vektor mit den RGBA-Werten des Fragments. Aber leider nur im Bereich 0.0f - 1.0f. Ich benötige für den Shader jedoch die "rohen" Byte-Daten zwischen 0 und 255.
    Ich wüsste nur gerne ob es da eine verlässliche Funktion gibt oder vielleicht sogar einen allgemein besseren Weg.

  4. #4
    Ich kenn mich zwar in dem Bereich nicht so gut aus, aber ich denke, dass auch hier die Werte nur als relative Werte zwischen 0 und 1 gespeichert werden, da der absolute Wert ja von der Farbtiefe abhängt.
    Also müsstest du ihn umrechnen, was aber nicht allzu schwer sein sollte.

    Code:
    uniform int MAX_VALUE = 255;
    
    [...]
    
    int convert(float value)
    {
    	return int(value * MAX_VALUE + 0.5);
    }
    Ich hoffe, die Syntax ist richtig. Ich hab mich noch nie mit GLSL beschäftigt. Mehr wird aber in der Grafikkarte wohl auch nicht passieren. Die + 0.5 ist das auf/abrunden.
    Wobei ich nicht so ganz verstehe, wofür du die Werte unbedingt als absolute Werte brauchst.

    Geändert von Whiz-zarD (19.01.2013 um 00:44 Uhr)

  5. #5
    Zitat Zitat von Whiz-zarD Beitrag anzeigen
    Wobei ich nicht so ganz verstehe, wofür du die Werte unbedingt als absolute Werte brauchst.
    Weil man mit Floats zwischen 0.0 und 1.0 nur sehr schwer in einem Array nachschauen kann so wie ich es vor habe.
    Was du beschreibst tue ich auch bereits in dem gezeigten Code, hier zum Beispiel:
    Code:
    int type = int(color.r * 255);
    Allerdings gibt es bei 32-bit Genauigkeit immer wieder Rundungsfehler.

  6. #6
    Achso, dafür gibt es logischerweise keine einfach lösung ohne Rundungsprobleme. Aber hast du denn so große Grafiken das Rundungsprobleme wirklich entstehen können?

  7. #7
    Ich wüsste auch nicht so wirklich, wieso da großartig Rundungsfehler auftauchen sollten. Hier wird doch eh auf ganze Zahlen gerundet. Ungenauer geht es doch eh schon fast nicht mehr.

  8. #8
    Zitat Zitat von R.D. Beitrag anzeigen
    Achso, dafür gibt es logischerweise keine einfach lösung ohne Rundungsprobleme. Aber hast du denn so große Grafiken das Rundungsprobleme wirklich entstehen können?
    Die Fehler entstehen ganz sicher, du kannst nicht alle 256 Zahlen anhand des Wertebereichs eines Floats zwischen 0.0 und 1.0 darstellen. Ich will dabei auf Nummer sicher gehen und nicht "hoffen" dass es funktioniert.

    Zitat Zitat von Whiz-zarD Beitrag anzeigen
    Ich wüsste auch nicht so wirklich, wieso da großartig Rundungsfehler auftauchen sollten. Hier wird doch eh auf ganze Zahlen gerundet. Ungenauer geht es doch eh schon fast nicht mehr.
    Man weis nie welche Hardware bei dem Benutzer verwendet wird und wie diese rundet. (175 / 255) * 255 kann bei zwei unterschiedlichen Grafikkarten ein unterschiedliches Ergebnis haben.

  9. #9
    Du musst nicht "hoffen", verlass dich einfach auf die Standards. Und teste:

    Code:
    #include <cassert>
    
    int main(int argc, char* argv[])
    {
        for (int i = 0; i < 256; ++i) {
            float f = (float)i / 255;
            int   n =  (int)(f * 255);
            assert(n == i);
        }
        return 0;
    }

  10. #10
    Zitat Zitat von Kyuu Beitrag anzeigen
    Du musst nicht "hoffen", verlass dich einfach auf die Standards. Und teste:

    Code:
    #include <cassert>
    
    int main(int argc, char* argv[])
    {
        for (int i = 0; i < 256; ++i) {
            float f = (float)i / 255;
            int   n =  (int)(f * 255);
            assert(n == i);
        }
        return 0;
    }
    Und falls das nicht passiert soll was geschehen? Das Spiel kann nicht bei dem Nutzer gespielt werden?
    Ich wüsste einfach nur gerne ob jemand sich mit GLSL auskennt um mir sagen zu können ob es eine Funktion gibt welche mir helfen könnte, oder um mir sagen zu können, dass es definitiv keine gibt und ich nicht weiter suchen sollte.

  11. #11
    Floating Point-Datentypen sind seit langer Zeit standardisiert und verhalten sich auf jedem Rechner gleich. Du siehst ein Problem, wo es keins gibt. Wie gesagt, verlass dich hier einfach auf die Standards.

  12. #12
    Wo genau sollen denn deiner Meinung die Rundungsfehler liegen? Floating Points gibt es ja nicht erst seit GLSL.

    Zitat Zitat von Kyuu Beitrag anzeigen
    Floating Point-Datentypen sind seit langer Zeit standardisiert und verhalten sich auf jedem Rechner gleich.
    Noch mal zur Vollständigkeitshalber:
    http://de.wikipedia.org/wiki/IEEE_754

    Geändert von Whiz-zarD (20.01.2013 um 17:45 Uhr)

  13. #13
    Er meint wahrscheinlich, dass bestimmte reelle Zahlen nicht exakt als Gleitkommazahlen dargestellt werden können. Das ist aber völlig irrelevant für seine Anwendung.

    Hier nochmal der Beweis:

    Code:
    #include <cstdio>
    
    int main(int argc, char* argv[])
    {
        FILE* f = fopen("output.txt", "w");
        for (int n1 = 0; n1 < 256; ++n1) {
            float n2 = (float)n1 / 255;
            int   n3 =  (int)(n2 * 255);
            fprintf(f, "%3d -> %.6f -> %3d: %s\n", n1, n2, n3, (n3 == n1 ? "OK!" : "ERROR!"));
        }
        fclose(f);
        return 0;
    }
    Ausgabe:

    Code:
      0 -> 0.000000 ->   0: OK!
      1 -> 0.003922 ->   1: OK!
      2 -> 0.007843 ->   2: OK!
      3 -> 0.011765 ->   3: OK!
      4 -> 0.015686 ->   4: OK!
      5 -> 0.019608 ->   5: OK!
      6 -> 0.023529 ->   6: OK!
      7 -> 0.027451 ->   7: OK!
      8 -> 0.031373 ->   8: OK!
      9 -> 0.035294 ->   9: OK!
     10 -> 0.039216 ->  10: OK!
     11 -> 0.043137 ->  11: OK!
     12 -> 0.047059 ->  12: OK!
     13 -> 0.050980 ->  13: OK!
     14 -> 0.054902 ->  14: OK!
     15 -> 0.058824 ->  15: OK!
     16 -> 0.062745 ->  16: OK!
     17 -> 0.066667 ->  17: OK!
     18 -> 0.070588 ->  18: OK!
     19 -> 0.074510 ->  19: OK!
     20 -> 0.078431 ->  20: OK!
     21 -> 0.082353 ->  21: OK!
     22 -> 0.086275 ->  22: OK!
     23 -> 0.090196 ->  23: OK!
     24 -> 0.094118 ->  24: OK!
     25 -> 0.098039 ->  25: OK!
     26 -> 0.101961 ->  26: OK!
     27 -> 0.105882 ->  27: OK!
     28 -> 0.109804 ->  28: OK!
     29 -> 0.113725 ->  29: OK!
     30 -> 0.117647 ->  30: OK!
     31 -> 0.121569 ->  31: OK!
     32 -> 0.125490 ->  32: OK!
     33 -> 0.129412 ->  33: OK!
     34 -> 0.133333 ->  34: OK!
     35 -> 0.137255 ->  35: OK!
     36 -> 0.141176 ->  36: OK!
     37 -> 0.145098 ->  37: OK!
     38 -> 0.149020 ->  38: OK!
     39 -> 0.152941 ->  39: OK!
     40 -> 0.156863 ->  40: OK!
     41 -> 0.160784 ->  41: OK!
     42 -> 0.164706 ->  42: OK!
     43 -> 0.168627 ->  43: OK!
     44 -> 0.172549 ->  44: OK!
     45 -> 0.176471 ->  45: OK!
     46 -> 0.180392 ->  46: OK!
     47 -> 0.184314 ->  47: OK!
     48 -> 0.188235 ->  48: OK!
     49 -> 0.192157 ->  49: OK!
     50 -> 0.196078 ->  50: OK!
     51 -> 0.200000 ->  51: OK!
     52 -> 0.203922 ->  52: OK!
     53 -> 0.207843 ->  53: OK!
     54 -> 0.211765 ->  54: OK!
     55 -> 0.215686 ->  55: OK!
     56 -> 0.219608 ->  56: OK!
     57 -> 0.223529 ->  57: OK!
     58 -> 0.227451 ->  58: OK!
     59 -> 0.231373 ->  59: OK!
     60 -> 0.235294 ->  60: OK!
     61 -> 0.239216 ->  61: OK!
     62 -> 0.243137 ->  62: OK!
     63 -> 0.247059 ->  63: OK!
     64 -> 0.250980 ->  64: OK!
     65 -> 0.254902 ->  65: OK!
     66 -> 0.258824 ->  66: OK!
     67 -> 0.262745 ->  67: OK!
     68 -> 0.266667 ->  68: OK!
     69 -> 0.270588 ->  69: OK!
     70 -> 0.274510 ->  70: OK!
     71 -> 0.278431 ->  71: OK!
     72 -> 0.282353 ->  72: OK!
     73 -> 0.286275 ->  73: OK!
     74 -> 0.290196 ->  74: OK!
     75 -> 0.294118 ->  75: OK!
     76 -> 0.298039 ->  76: OK!
     77 -> 0.301961 ->  77: OK!
     78 -> 0.305882 ->  78: OK!
     79 -> 0.309804 ->  79: OK!
     80 -> 0.313726 ->  80: OK!
     81 -> 0.317647 ->  81: OK!
     82 -> 0.321569 ->  82: OK!
     83 -> 0.325490 ->  83: OK!
     84 -> 0.329412 ->  84: OK!
     85 -> 0.333333 ->  85: OK!
     86 -> 0.337255 ->  86: OK!
     87 -> 0.341176 ->  87: OK!
     88 -> 0.345098 ->  88: OK!
     89 -> 0.349020 ->  89: OK!
     90 -> 0.352941 ->  90: OK!
     91 -> 0.356863 ->  91: OK!
     92 -> 0.360784 ->  92: OK!
     93 -> 0.364706 ->  93: OK!
     94 -> 0.368627 ->  94: OK!
     95 -> 0.372549 ->  95: OK!
     96 -> 0.376471 ->  96: OK!
     97 -> 0.380392 ->  97: OK!
     98 -> 0.384314 ->  98: OK!
     99 -> 0.388235 ->  99: OK!
    100 -> 0.392157 -> 100: OK!
    101 -> 0.396078 -> 101: OK!
    102 -> 0.400000 -> 102: OK!
    103 -> 0.403922 -> 103: OK!
    104 -> 0.407843 -> 104: OK!
    105 -> 0.411765 -> 105: OK!
    106 -> 0.415686 -> 106: OK!
    107 -> 0.419608 -> 107: OK!
    108 -> 0.423529 -> 108: OK!
    109 -> 0.427451 -> 109: OK!
    110 -> 0.431373 -> 110: OK!
    111 -> 0.435294 -> 111: OK!
    112 -> 0.439216 -> 112: OK!
    113 -> 0.443137 -> 113: OK!
    114 -> 0.447059 -> 114: OK!
    115 -> 0.450980 -> 115: OK!
    116 -> 0.454902 -> 116: OK!
    117 -> 0.458824 -> 117: OK!
    118 -> 0.462745 -> 118: OK!
    119 -> 0.466667 -> 119: OK!
    120 -> 0.470588 -> 120: OK!
    121 -> 0.474510 -> 121: OK!
    122 -> 0.478431 -> 122: OK!
    123 -> 0.482353 -> 123: OK!
    124 -> 0.486275 -> 124: OK!
    125 -> 0.490196 -> 125: OK!
    126 -> 0.494118 -> 126: OK!
    127 -> 0.498039 -> 127: OK!
    128 -> 0.501961 -> 128: OK!
    129 -> 0.505882 -> 129: OK!
    130 -> 0.509804 -> 130: OK!
    131 -> 0.513726 -> 131: OK!
    132 -> 0.517647 -> 132: OK!
    133 -> 0.521569 -> 133: OK!
    134 -> 0.525490 -> 134: OK!
    135 -> 0.529412 -> 135: OK!
    136 -> 0.533333 -> 136: OK!
    137 -> 0.537255 -> 137: OK!
    138 -> 0.541176 -> 138: OK!
    139 -> 0.545098 -> 139: OK!
    140 -> 0.549020 -> 140: OK!
    141 -> 0.552941 -> 141: OK!
    142 -> 0.556863 -> 142: OK!
    143 -> 0.560784 -> 143: OK!
    144 -> 0.564706 -> 144: OK!
    145 -> 0.568627 -> 145: OK!
    146 -> 0.572549 -> 146: OK!
    147 -> 0.576471 -> 147: OK!
    148 -> 0.580392 -> 148: OK!
    149 -> 0.584314 -> 149: OK!
    150 -> 0.588235 -> 150: OK!
    151 -> 0.592157 -> 151: OK!
    152 -> 0.596078 -> 152: OK!
    153 -> 0.600000 -> 153: OK!
    154 -> 0.603922 -> 154: OK!
    155 -> 0.607843 -> 155: OK!
    156 -> 0.611765 -> 156: OK!
    157 -> 0.615686 -> 157: OK!
    158 -> 0.619608 -> 158: OK!
    159 -> 0.623529 -> 159: OK!
    160 -> 0.627451 -> 160: OK!
    161 -> 0.631373 -> 161: OK!
    162 -> 0.635294 -> 162: OK!
    163 -> 0.639216 -> 163: OK!
    164 -> 0.643137 -> 164: OK!
    165 -> 0.647059 -> 165: OK!
    166 -> 0.650980 -> 166: OK!
    167 -> 0.654902 -> 167: OK!
    168 -> 0.658824 -> 168: OK!
    169 -> 0.662745 -> 169: OK!
    170 -> 0.666667 -> 170: OK!
    171 -> 0.670588 -> 171: OK!
    172 -> 0.674510 -> 172: OK!
    173 -> 0.678431 -> 173: OK!
    174 -> 0.682353 -> 174: OK!
    175 -> 0.686275 -> 175: OK!
    176 -> 0.690196 -> 176: OK!
    177 -> 0.694118 -> 177: OK!
    178 -> 0.698039 -> 178: OK!
    179 -> 0.701961 -> 179: OK!
    180 -> 0.705882 -> 180: OK!
    181 -> 0.709804 -> 181: OK!
    182 -> 0.713726 -> 182: OK!
    183 -> 0.717647 -> 183: OK!
    184 -> 0.721569 -> 184: OK!
    185 -> 0.725490 -> 185: OK!
    186 -> 0.729412 -> 186: OK!
    187 -> 0.733333 -> 187: OK!
    188 -> 0.737255 -> 188: OK!
    189 -> 0.741176 -> 189: OK!
    190 -> 0.745098 -> 190: OK!
    191 -> 0.749020 -> 191: OK!
    192 -> 0.752941 -> 192: OK!
    193 -> 0.756863 -> 193: OK!
    194 -> 0.760784 -> 194: OK!
    195 -> 0.764706 -> 195: OK!
    196 -> 0.768627 -> 196: OK!
    197 -> 0.772549 -> 197: OK!
    198 -> 0.776471 -> 198: OK!
    199 -> 0.780392 -> 199: OK!
    200 -> 0.784314 -> 200: OK!
    201 -> 0.788235 -> 201: OK!
    202 -> 0.792157 -> 202: OK!
    203 -> 0.796078 -> 203: OK!
    204 -> 0.800000 -> 204: OK!
    205 -> 0.803922 -> 205: OK!
    206 -> 0.807843 -> 206: OK!
    207 -> 0.811765 -> 207: OK!
    208 -> 0.815686 -> 208: OK!
    209 -> 0.819608 -> 209: OK!
    210 -> 0.823529 -> 210: OK!
    211 -> 0.827451 -> 211: OK!
    212 -> 0.831373 -> 212: OK!
    213 -> 0.835294 -> 213: OK!
    214 -> 0.839216 -> 214: OK!
    215 -> 0.843137 -> 215: OK!
    216 -> 0.847059 -> 216: OK!
    217 -> 0.850980 -> 217: OK!
    218 -> 0.854902 -> 218: OK!
    219 -> 0.858824 -> 219: OK!
    220 -> 0.862745 -> 220: OK!
    221 -> 0.866667 -> 221: OK!
    222 -> 0.870588 -> 222: OK!
    223 -> 0.874510 -> 223: OK!
    224 -> 0.878431 -> 224: OK!
    225 -> 0.882353 -> 225: OK!
    226 -> 0.886275 -> 226: OK!
    227 -> 0.890196 -> 227: OK!
    228 -> 0.894118 -> 228: OK!
    229 -> 0.898039 -> 229: OK!
    230 -> 0.901961 -> 230: OK!
    231 -> 0.905882 -> 231: OK!
    232 -> 0.909804 -> 232: OK!
    233 -> 0.913725 -> 233: OK!
    234 -> 0.917647 -> 234: OK!
    235 -> 0.921569 -> 235: OK!
    236 -> 0.925490 -> 236: OK!
    237 -> 0.929412 -> 237: OK!
    238 -> 0.933333 -> 238: OK!
    239 -> 0.937255 -> 239: OK!
    240 -> 0.941176 -> 240: OK!
    241 -> 0.945098 -> 241: OK!
    242 -> 0.949020 -> 242: OK!
    243 -> 0.952941 -> 243: OK!
    244 -> 0.956863 -> 244: OK!
    245 -> 0.960784 -> 245: OK!
    246 -> 0.964706 -> 246: OK!
    247 -> 0.968627 -> 247: OK!
    248 -> 0.972549 -> 248: OK!
    249 -> 0.976471 -> 249: OK!
    250 -> 0.980392 -> 250: OK!
    251 -> 0.984314 -> 251: OK!
    252 -> 0.988235 -> 252: OK!
    253 -> 0.992157 -> 253: OK!
    254 -> 0.996078 -> 254: OK!
    255 -> 1.000000 -> 255: OK!

  14. #14
    Ich habe gerade einen Shader geschrieben und es getestet.
    Wie es scheint werden wirklich alle 256 verschiedenen Farbstärken korrekt dargestellt, zumindest bei mir.
    Augenscheinlich war die Einstellung meines Grafikprogramms beim ersten Test für den Fehler verantwortlich, durch Kompression oder sonstiges wurden wohl mehrere Farben welche zu nah aneinander lagen zusammen gelegt.
    Vielen Dank für die Antworten.

  15. #15
    Zitat Zitat von Cornix Beitrag anzeigen
    Ich habe gerade einen Shader geschrieben und es getestet.
    Wie es scheint werden wirklich alle 256 verschiedenen Farbstärken korrekt dargestellt, zumindest bei mir.
    Okay du hast das wohl nicht gelesen, aber nicht nur bei dir, bei JEDEM. Finde mir einen Rechner der dir da andere Werte ausspuckt und du hast einen Preis verdient.

    Hier noch mal der Kommentar von Kyuu:
    Zitat Zitat von Kyuu Beitrag anzeigen
    Floating Point-Datentypen sind seit langer Zeit standardisiert und verhalten sich auf jedem Rechner gleich. Du siehst ein Problem, wo es keins gibt. Wie gesagt, verlass dich hier einfach auf die Standards.

  16. #16
    Zitat Zitat von Cornix Beitrag anzeigen
    Augenscheinlich war die Einstellung meines Grafikprogramms beim ersten Test für den Fehler verantwortlich, durch Kompression oder sonstiges wurden wohl mehrere Farben welche zu nah aneinander lagen zusammen gelegt.
    Vielen Dank für die Antworten.
    Da waren vermutlich Farbprofile am Werk.

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •