2010-08-25 17 views
22

Il mio problema è ottenere più di una trama accessibile in uno shader GLSL. Ecco quello che sto facendo:Più trame in GLSL - solo una funziona

Shader:

uniform sampler2D sampler0; 
uniform sampler2D sampler1; 
uniform float blend; 
void main(void) 
{ 
    vec2 coords = gl_TexCoord[0]; 
    vec4 col = texture2D(sampler0, coords); 
    vec4 col2 = texture2D(sampler1, coords); 
    if (blend > 0.5){ 
     gl_FragColor = col; 
    } else { 
     gl_FragColor = col2; 
    } 
}; 

Così, ho semplicemente scegliere tra i due valori di colore sulla base di una variabile uniforme. Abbastanza semplice (questo è un test), ma al posto del comportamento previsto, ottengo tutto nero quando si miscela < = 0,5 .

codice OpenGL:

m_sampler0location = m_shader.FindUniform("sampler0"); 
m_sampler1location = m_shader.FindUniform("sampler1"); 
m_blendlocation = m_shader.FindUniform("blend"); 

glActiveTexture(GL_TEXTURE0); 
glEnable(GL_TEXTURE_2D); 
m_extensions.glUniform1iARB(m_sampler0location, 0); 
glBindTexture(GL_TEXTURE_2D, Texture0.Handle); 
glActiveTexture(GL_TEXTURE1); 
glEnable(GL_TEXTURE_2D); 
m_extensions.glUniform1iARB(m_sampler1location, 1); 
glBindTexture(GL_TEXTURE_2D, Texture1.Handle); 
glBegin(GL_QUADS); 
    //lower left 
    glTexCoord2f(0, 0); 
    glVertex2f(-1.0, -1.0); 
    //upper left 
    glTexCoord2f(0, maxCoords0.t); 
    glVertex2f(-1.0, 1.0); 
    //upper right 
    glTexCoord2f(maxCoords0.s, maxCoords0.t); 
    glVertex2f(1.0, 1.0); 
    //lower right 
    glTexCoord2f(maxCoords0.s, 0); 
    glVertex2f(1.0, -1.0); 
glEnd() 

Lo shader viene compilato e legato prima di tutto questo. Tutti i controlli di integrità in quel processo indicano che va bene. Come ho già detto, il valore di col nel programma shader riflette i frammenti di una trama; il valore di col2 è nero. La trama visualizzata è l'ultima trama attiva: se cambio l'ultimo glBindTexture per il binding Texture0.Handle, la trama cambia. Risolto in base alla risposta di Bahbar.

Allo stato attuale, la scena viene visualizzata in nero, anche se aggiungo qualcosa come gl_FragColor.r = blend; come ultima riga dello shader. Tuttavia, se commento la chiamata glActiveTexture(GL_TEXTURE1);, lo shader funziona di nuovo e la stessa texture appare sia in sampler0 che in sampler1.

Cosa sta succedendo? La linea in questione, glActiveTexture(GL_TEXTURE1);, sembra funzionare correttamente, come evidenziato da un successivo glGetIntegerv(GL_ACTIVE_TEXTURE, &anint). Perché rompe tutto così orribilmente? Ho già provato ad aggiornare i miei driver di visualizzazione.

+0

Hai trovato una soluzione al tuo problema? Ho lo stesso identico problema. – Andrea3000

+0

Sì, la soluzione con tag ha funzionato per me. – appas

risposta

24

Ecco un esempio GLUT di base (scritto su OS X, adattato secondo necessità) che genera due trame a scacchiera, carica uno shader con due campionatori e li combina colorandone uno (uno rosso, uno blu) e unendo. Vedere se questo funziona per voi:

#include <stdio.h> 
#include <stdlib.h> 

#include <GLUT/glut.h> 
#include <OpenGL/gl.h> 
#include <OpenGL/glu.h> 

#define kTextureDim 64 

GLuint t1; 
GLuint t2; 

/* adapted from the red book */ 
GLuint makeCheckTex() { 
    GLubyte image[kTextureDim][kTextureDim][4]; // RGBA storage 

    for (int i = 0; i < kTextureDim; i++) { 
     for (int j = 0; j < kTextureDim; j++) { 
      int c = ((((i & 0x8) == 0)^((j & 0x8)) == 0))*255; 
      image[i][j][0] = (GLubyte)c; 
      image[i][j][1] = (GLubyte)c; 
      image[i][j][2] = (GLubyte)c; 
      image[i][j][3] = (GLubyte)255; 
     } 
    } 

    GLuint texName; 
    glGenTextures(1, &texName);  
    glBindTexture(GL_TEXTURE_2D, texName); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kTextureDim, kTextureDim, 0, GL_RGBA, GL_UNSIGNED_BYTE, image); 

    return texName; 
} 

void loadShader() { 
#define STRINGIFY(A) #A 

    const GLchar* source = STRINGIFY(

            uniform sampler2D tex1; 
            uniform sampler2D tex2; 

            void main() { 
             vec4 s1 = texture2D(tex1, gl_TexCoord[0].st); 
             vec4 s2 = texture2D(tex2, gl_TexCoord[0].st + vec2(0.0625, 0.0625)); 
             gl_FragColor = mix(vec4(1, s1.g, s1.b, 0.5), vec4(s2.r, s2.g, 1, 0.5), 0.5); 
            } 

            ); 

    GLuint program = glCreateProgram(); 
    GLuint shader = glCreateShader(GL_FRAGMENT_SHADER); 
    glShaderSource(shader, 1, &source, NULL); 
    glCompileShader(shader); 

    GLint logLength; 
    glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength); 
    if (logLength > 0) { 
     GLchar* log = (GLchar*)malloc(logLength); 
     glGetShaderInfoLog(shader, logLength, &logLength, log); 
     printf("Shader compile log:\n%s\n", log); 
     free(log); 
    } 

    glAttachShader(program, shader); 
    glLinkProgram(program); 

    glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength); 
    if (logLength > 0) { 
     GLchar* log = (GLchar*)malloc(logLength); 
     glGetProgramInfoLog(program, logLength, &logLength, log); 
     printf("Program link log:\n%s\n", log); 
     free(log); 
    } 

    GLuint t1Location = glGetUniformLocation(program, "tex1"); 
    GLuint t2Location = glGetUniformLocation(program, "tex2"); 

    glUniform1i(t1Location, 0); 
    glUniform1i(t2Location, 1); 

    glUseProgram(program); 
} 


void init() 
{ 
    glClearColor(0.0, 0.0, 0.0, 0.0); 
    glEnable(GL_DEPTH_TEST); 
    glShadeModel(GL_FLAT); 

    t1 = makeCheckTex(); 
    t2 = makeCheckTex(); 

    loadShader(); 
} 


void display() 
{ 
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
    glLoadIdentity(); 

    glActiveTexture(GL_TEXTURE0); 
    glEnable(GL_TEXTURE_2D); 
    glBindTexture(GL_TEXTURE_2D, t1); 

    glActiveTexture(GL_TEXTURE1); 
    glBindTexture(GL_TEXTURE_2D, t2); 

    glBegin(GL_QUADS); 
    //lower left 
    glTexCoord2f(0, 0); 
    glVertex2f(-1.0, -1.0); 
    //upper left 
    glTexCoord2f(0, 1.0); 
    glVertex2f(-1.0, 1.0); 
    //upper right 
    glTexCoord2f(1.0, 1.0); 
    glVertex2f(1.0, 1.0); 
    //lower right 
    glTexCoord2f(1.0, 0); 
    glVertex2f(1.0, -1.0); 
    glEnd(); 

    glutSwapBuffers(); 
} 


void reshape(int w, int h) 
{ 
    glViewport(0, 0, w, h); 
    glMatrixMode(GL_PROJECTION); 
    glLoadIdentity(); 
    glOrtho(-2, 2, -2, 2, -2, 2); 
    glMatrixMode(GL_MODELVIEW); 
    glLoadIdentity(); 
} 


int main(int argc, char **argv) 
{ 
    glutInit(&argc, argv); 

    glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGBA); 

    glutInitWindowSize(512, 512); 
    glutInitWindowPosition(0, 0); 

    glutCreateWindow("GLSL Texture Blending"); 

    glutReshapeFunc(reshape); 
    glutDisplayFunc(display); 
    glutIdleFunc(display); 

    init(); 

    glutMainLoop(); 
    return 0; 
} 

Speriamo che il risultato sarà simile a questa (si può commentare la chiamata glUseProgram per vedere il primo tessuto disegnato senza shader): alt text

+0

Ok, questo funziona. Grazie mille, ora ho una base da cui lavorare per cercare di capire il problema nel mio programma. – appas

+1

Perché le uniformi all'interno dello shader sono denominate "tex0, tex1", ma quando si chiama "glGetUniformLocation" vengono denominate "tex1, tex2"? – Chris

+1

Una domanda migliore potrebbe essere: come mai funziona, anche se la posizione di ritorno di una delle uniformi è "-1"? Ho provato a impostare i nomi uniformi su qualsiasi stringa e funzionerà ancora - chiunque potrebbe spiegarlo, per favore? – Chris

0

Sembra che la tua chiamata glActiveTexture non funzioni. Sei sicuro di aver impostato correttamente il puntatore della funzione?

Verificare chiamando glGetIntegerv(GL_ACTIVE_TEXTURE, &anint) dopo aver chiamato glActiveTexture (GL_TEXTURE1).

Anche glEnable(GL_TEXTURE_2D) non sono utili. Lo shader stesso specifica quali unità di texture usare e quale target di ogni unità deve "abilitare".


Modifica per aggiungere:

Bene, la vostra nuova situazione è particolare. Il fatto che non puoi nemmeno mostrare il rosso è strano, in particolare (beh, hai impostato alpha su 1 solo per essere sicuro?).

Detto questo, è necessario ripristinare GL_TEXTURE0 come il glActiveTexture dopo aver finito l'impostazione l'unità texture 1 (vale a dire dopo la chiamata glBindTexture).

+0

Forse sta mixando enum dall'estensione ARB con funzionalità di base (la funzione)? Strano davvero. –

+1

Grazie per la rapida risposta. Avevi ragione: GL_ACTIVE_TEXTURE non era impostato correttamente. Ora ho corretto il puntatore della funzione e il valore cambia come dovrebbe, ma ora tutto ciò che ottengo è nero. Ho aggiornato la domanda con la mia nuova situazione. – appas

+0

@Mads Elvheim: chiarito l'ultima frase. – Bahbar

2

Quando si compila il tuo shader da testare, ho trovato due errori:

  1. coords deve essere assegnata la parte st dei 4 componenti gl_TexCoord, per esempio

    vec2 coords = gl_TexCoord[0].st; 
    
  2. Lo shader non dovrebbe finire con un punto e virgola.

Stai verificando in qualsiasi punto del programma principale che lo shader compila correttamente? Si consiglia di guardare GL_COMPILE_STATUS tramite glGetShader e glGetShaderInfoLog.

+0

Ok, bene ho cambiato il compito ma non ha avuto alcun effetto. Il punto e virgola era un errore di battitura, quindi l'ho rimosso dal messaggio originale. Ho già verificato 'GL_COMPILE_STATUS', e lo shader compila e si lega correttamente in tutti i casi, ma funziona solo se ometto la riga' glActiveTexture (GL_TEXTURE1); '- anche se sostituisco il tutto con un oneliner che solo uscite bianche. – appas

8

piuttosto tardi la risposta, ma per chiunque si sia imbattuto in questo - ho riscontrato lo stesso problema e dopo un breve giochetto, mi sono reso conto che chiamare glActiveTexture(GL_TEXTURE0) risolve il problema. Sembra che qualcosa sulla linea venga confusa se l'unità di texture attiva non viene "ripristinata" a zero. Questo potrebbe essere essere un comportamento dipendente dal sistema; Sto usando Archlinux a 64 bit con Mesa 8.0.4.

+0

Ho risolto anche un problema correlato a quello che stavo facendo. Very bizarro –

+0

Un vero live saver! Ho esaminato il mio codice, decostruendolo fino a quando non ho eseguito una ricerca incrociata e ho cercato ovunque nei documenti e online e non sono riuscito a trovare un singolo errore. Avrei dovuto rinunciare x 100 se potessi, John: ^) (win7 64 bit GTX780) – yapdog

10

Solo per aiutare altre persone che potrebbero essere interessate a utilizzare più trame e si sentiranno senza speranza dopo giorni alla ricerca di una risposta. Ho scoperto che è necessario chiamare

glUseProgram(program); 

GLuint t1Location = glGetUniformLocation(program, "tex1"); 
GLuint t2Location = glGetUniformLocation(program, "tex2"); 

glUniform1i(t1Location, 0); 
glUniform1i(t2Location, 1); 

In tal modo per farlo funzionare (glUseProgram è l'ultima istruzione per il 99% del codice di esempio che ho trovato on-line). Ora potrebbe essere solo il mio caso e non influenzare nessun altro sulla Terra, ma nel caso pensassi di condividerlo.

+1

è giusto, la pagina man dice "glUniform opera sull'oggetto programma che è stato reso parte dello stato attuale chiamando glUseProgram()" –

+0

questo non ha funzionato per me (in OpenGL 2.0/GLSL 1.2), ma glGetUniformLocation/glUseProgram/glUniform1i ha fatto - http://stackoverflow.com/a/25252981/236081 – d3vid