Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

1

26.05.2012, 10:56

[GELÖST] GLSL glTexture2D textur koordinaten

Hi,

Ich versuche mich gerade zum ersten mal mit der Nutzung eines Shaders. Benutzt wird nur der Fragment Shader, der Vertex Shader wird nicht gebraucht da das ganze auf 2D Ebene läuft.

Der Shader soll aus der gl_FragCoord Variable (bei einer Aufösung von 640*480) die richtigen Texturkoordinaten einer Textur mit der Größe 160*120 herauslesen und dann nach beachten dass der eine schwarze Linie rechts und unten von den erzeugten 4*4 Quadraten sein soll.

Die 160*120 Textur wird im C++ Program erzeugt und völlig weiß gefärbt. Eingebunden wird sie dann mit:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
worldTexID=gfx->CreateTexture(160,120).id;

    int texIDVar=glGetUniformLocation(renderShader.program,"world");

    gfx->UseShader(renderShader);

    glUniform1ui(texIDVar,worldTexID);

    gfx->StopShader();


Der Shader sieht folgendermaßen aus:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
uniform sampler2D world;



vec2 cellPos;

vec2 cellTexPos;

vec4 cellColor;



void main (void)

{

    cellPos.x=float(int(gl_FragCoord.x/4.0));

    cellPos.y=float(int(gl_FragCoord.y/4.0));

    cellTexPos.x=float(int(cellPos.x*4.0))*(1.0/160.0);

    cellTexPos.y=float(int(cellPos.y*4.0))*(1.0/120.0);

    cellColor=texture2D(world,vec2(int(cellPos.x*4.0),int(cellPos.y*4.0)));

    if ((int(cellPos.x*4.0)==int(gl_FragCoord.x))||

        (int(cellPos.y*4.0)==int(gl_FragCoord.y)))

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

    else

        gl_FragColor=cellColor;

}


Anscheinend sind aber die Texturkoordinaten falsch denn als Ausgabe bekomme ich nur Schwarz zu sehen. Wenn ich cellColor mit einer anderen konstanten Farbe ersetze wird diese richtig angezeigt (+ umrandung)

Wisst ihr was dort falsch ist?

Mfg Helco

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Helco« (28.05.2012, 10:38)


Beiträge: 1 223

Wohnort: Deutschland Bayern

Beruf: Schüler

  • Private Nachricht senden

2

26.05.2012, 11:48

Ich kann dir zwar nicht direkt bei deinem eigentlichen Problem helfen, habe aber ein paar Tipps:
  1. Mache nur Variablen global wenn sie es wirklich sein müssen und das ist in der Shaderprogrammierung eigentlich nie der Fall.
  2. "float(int(" ist evt. lahm und es kann zu Überläufen kommen. Für das was du machen willst, gibt es die "floor()"-Funktion.

  3. Anstatt Dem Integervergleich der einzelnen Komponenten mache besser einen normalen Vergleich: "any(lessThan(abs(cellPos.xy*4.0-gl_FragCoord.xy),vec2(1.0,1.0)))"
    Wobei mir dieses Konstrukt sowieso komisch vorkommt und wahrscheinlich auch immer True zurückliefert.
    Eventuell kommt deshalb nicht die gewünschte Ausgabe.

  4. Außerdem sollte man in der Regel immer VS und FS verwenden.

Integer solltest du in Shadern sowieso immer so gut es irgendwie geht vermeiden.

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

3

26.05.2012, 11:48

Du hast offenbar ein kleines Missverständnis was den sampler2D angeht. Du weißt dem Uniform nicht die id der Textur zu, sondern den Index der Texture in die die Textur gebunden wird. Also z.B. so:

C-/C++-Quelltext

1
2
3
glUniform1ui(texIDVar, 0);
glActiveTexture(G_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, worldTexID);

4

26.05.2012, 14:19

Okay erst mal vielen Dank für die ganzen Hinweise. Ich habe versucht alle eure Tipps zu berücksichtigen und habe den Code geändert.
Shader:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
uniform sampler2D world; 
void main (void) 

{ 

vec2 cellPos; 

vec2 cellTexPos; 

vec4 cellColor; 



cellPos.x=floor(gl_FragCoord.x/8.0); 

cellPos.y=floor(gl_FragCoord.y/8.0); 

cellTexPos.x=floor(cellPos.x*8.0)*(1.0/80.0); 

cellTexPos.y=floor(cellPos.y*8.0)*(1.0/60.0); 

cellColor=texture2D(world,cellTexPos); 

if ((floor(cellPos.x*8.0)==floor(gl_FragCoord.x))|| 

 (floor(cellPos.y*8.0)==floor(gl_FragCoord.y))) 

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

else 

 gl_FragColor=cellColor; 

}


Einbinden mit C++:



C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
worldTexID=gfx->CreateTexture(80,60).id; 

int texIDVar=glGetUniformLocation(renderShader.program,"world"); 

gfx->UseShader(renderShader); 

glUniform1ui(texIDVar, 1); 

glActiveTexture(GL_TEXTURE1); 

glBindTexture(GL_TEXTURE_2D, worldTexID); 

glActiveTexture(GL_TEXTURE0); 

gfx->StopShader();

Zusätzlich hab ich gemerkt dass wenn man die gewünschte Umrandung weiß zeichnen lässt das auch so funktioniert wie es soll. Außerdem sind 160*120 Kästchen viel zu klein deswegen hab ich dies runtergesetzt auf 80*60.
Ein Vertexshader gibt es auch allerdings besteht der nur aus

C-/C++-Quelltext

1
2
3
4
5
6
7
void main() 

{ 

gl_Position=ftransform(); 

}

da ich nur 4 Vertices zeichnen lasse.

Ich musste die Textur "worldTexID" auf GL_TEXTURE1 schalten da ich zum zeichnen in C++ lediglich ein weißes Rechteck zeichnen lasse und die eigentliche Arbeit dem Shader überlasse:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//Render 
gfx->UseShader(renderShader); 
glBindTexture(GL_TEXTURE_2D,0); 

glColor3f(1.0f,1.0f,1.0f); 

glBegin(GL_QUADS); 

glVertex2f(0.0f,0.0f); 

glVertex2f(640.0f,0.0f); 

glVertex2f(640.0f,480.0f); 
glVertex2f(0.0f,480.0f); 
glEnd(); 
gfx->StopShader();

Eine weitere vielleicht nützliche Information wäre, dass ich das in einen Framebuffer zeichnen lasse um die Rechenarbeit nicht jedes machen lassen muss.

EDIT: es stellte sich heraus dass die berechneten textur koordinaten richtig sind. Mit einem Zusatz konnte ich genau die Kästchen grün färben die bestimmte textur koordinaten haben müssten und diese auch haben:

C-/C++-Quelltext

1
2
3
else if (cellTexPos.x>0.0125&&cellTexPos.x<0.0625&&
             cellTexPos.y>0.0166667&&cellTexPos.y<0.083333)
        gl_FragColor=vec4(0.0,1.0,0.0,1.0);

Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »Helco« (26.05.2012, 16:19)


dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

5

26.05.2012, 20:50

Hast du auch einen Texturfilter gesetzt?

6

26.05.2012, 22:57

Ja sowohl die framebuffer Textur (640*480) als auch die "world" Textur (80*60) haben GL_NEAREST auf Dem MIN und dem MAG Filter.
Diese Texture werden allerdings nicht vergrößert oder verkleinert...

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

7

27.05.2012, 01:16

Oh, Moment...gibt's jetzt eigentlich noch ein Problem oder funktioniert es mittlerweile?

8

27.05.2012, 08:24

Ja es gibt immer noch ein Problem: Alle Pixel die aus der Textur im Shader herausgelesen werden sind schwarz... Da ich die Textur allerdings völlig weiß gefärbt habe, stimmt immer noch etwas nicht



Gefärbt habe ich mit:


C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//Update world texture
    unsigned char* pixel=(unsigned char*)malloc(80*60*3);
    int i;unsigned char id;
    for (int y=0;y<80;y++) {
        for (int x=0;x<60;x++) {
            i=y*80+x;
            id=world->plants[(y+offset.y)*world->size+x+offset.x];
            pixel[i]=GetColorR(id);
            pixel[i+1]=GetColorG(id);
            pixel[i+2]=GetColorB(id);
            if (pixel[i]!=255||pixel[i+1]!=255||pixel[i+2]!=255)
                cout << x << "," << y << ":R" << short(pixel[i]) << " G" << short(pixel[i+1]);
        }
    }
    glBindTexture(GL_TEXTURE_2D,worldTexID);
    glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,80,60,0,GL_RGB,GL_UNSIGNED_BYTE,pixel);
    free(pixel);
Dabei habe ich mir mit der im Moment auskommentierten Zeile den Wert den ich dann in die Textur einsetze anzeigen lassen: immer 255



EDIT: Wenn ich mir mit

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
glGetTexImage(GL_TEXTURE_2D,0,GL_RGB,GL_UNSIGNED_BYTE,pixel);

    ofstream fout ("log.txt");

    for (int i=0;i<4800;i+=3)

        if (pixel[i]!=255||pixel[i+1]!=255||pixel[i+2]!=255)

            fout << (i%80) << "," << (i/60) << ":R" << short(pixel[i]) << " G" << short(pixel[i+1]) << " B" << short(pixel[i+2]) << endl;

    fout.close();
Direkt nach dem oben genannten code ("free(pixel);" natürlich weg) mir alle die Pixel anzeigen lasse die nicht weiß sind kommt:



EDIT: sehr viele Pixel (aber nicht alle) mit zufällig aussehenden Farbwerten. Aufgrund eines Problems bei meinem Browser mit dem Forum oder vom Forum werden vor allem bei Code-Feldern immer leere Zeilen eingefügt was zu einem riiiiiiiiesigen Post geführt hatte. Wer die Liste von den ausgegebenen Pixel haben will, dem kann ich sie per PM schicken

Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von »Helco« (27.05.2012, 11:58)


9

27.05.2012, 17:29

(Entschuldigung für den Doppelpost aber man siehe Erklärung direkt über dies und den auftretenden Fehler in den letzten Posts von mir auf der mich gerade nur noch nervt)

Ich habe jetzt herausgefunden dass etwas mit dem Updaten der Textur nicht stimmt und deswegen Pixel falsche Farben haben (die aber nicht angezeigt werden). "glGetError" gibt "GL_INVALID_OPERATION" aus direkt nach dem "glTexImage2D" (Post 8, Zeile 16)

Anscheinend passiert der fehler früher...

Okay das ganze ist zur Hälfte gelöst:
wenn ich die "worldTex" uniform Variable an den Shader schicke benutze ich immer noch glUniform1ui ,da eine Textur ID ja ein "unsigned int" ist. Anscheinend ist eine sampler ID vom Typ "int" sodass ich das ganze einfach in "glUniform1" ändern muss und die Textur kann im Shader richtig benutzt werden.
Jetzt kommt allerdings noch ein Problem: Die ganzen nicht-weißen Pixel die ich mir ausgegeben habe stimmen leider, das heißt ich habe ein Bild mit 6-7 verschiedenen Farben.

(Link)

Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »Helco« (27.05.2012, 19:24)


10

28.05.2012, 10:03

Update über Update:
Vorläufig konnte man das Problem lösen indem man die uninitalisierte "pixel" variable auf einen bestimmten wert setzt, allerdings ist der blaue punkt auf dem obrigen Bild teilweise sogar richtig.Aber:
1. er ist blau. Das war der Fehler der auch den Rest verursacht hat, denn man muss bei dem Updaten der "worldTexID" Textur bedenken dass "y*80+x" nur den Index des Pixels gibt wenn man mit 8 Bit Bildern arbeitet. Da ich hier mit 24 Bit Bildern arbeite ersetzt man es durch "(y*80+x)*3" und auch ohne Initialisierung per "memset" ist das Bild schön weiß, der blaue Punkt sitzt an der richtigen Stelle und ist nicht blau sondern grün, so wie ich es will.
2. der blaue Punkt ist zu groß, er sollte nur ein Kästchen beinhalten nicht 4 Dieser Fehler ist noch nicht gelöst, liegt aber am Shader
EDIT: Egal ob er am Shader liegt, ich hab entdeckt, dass das viel einfacher genauso funktioniert, vermutlich sogar noch schneller und mit weniger Speicherverbrauch. Kein Framebuffer mehr, keine 640*480 Textur. Die 80*60 Textur wird mit dem GL_NEAREST Filter vergrößert und so auf den Bildschirm gebracht -> Kästchen mit den richtigen Farben am richtigen Ort mit richtiger Größe
Der Shader der dabei angeschaltet ist fügt die schwarzen Umrandungen noch dazu.
Und damit ist alles was ich gewollt habe und noch mehr (schneller und weniger GRAM/RAM) erreicht.

Vielen Danke trotzdem für die Hinweise

Mfg Helco

Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »Helco« (28.05.2012, 10:59)


Werbeanzeige