2010-08-25 9 views
22

Mi problema es obtener más de una textura accesible en un sombreador GLSL. Esto es lo que estoy haciendo:Múltiples texturas en GLSL: solo funciona

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; 
    } 
}; 

Por lo tanto, sólo tiene que elegir entre los dos valores de color en base a una variable uniforme. Bastante simple (esta es una prueba), pero en lugar del comportamiento esperado, obtengo todo negro cuando combine < = 0.5 .

código 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() 

El shader se compila y se comprometieron antes de todo esto. Todos los controles de cordura en ese proceso indican que va bien. Como dije, el valor de col en el programa de sombreado refleja fragmentos de una textura; el valor de col2 es negro. La textura que se muestra es la última textura activa; si cambio el último glBindTexture para vincular Texture0.Handle, la textura cambia. Solucionado de acuerdo con la respuesta de Bahbar.

Como está, la escena se vuelve negra, incluso si agrego algo como gl_FragColor.r = blend; como la última línea del sombreador. Pero si hago un comentario sobre la llamada glActiveTexture(GL_TEXTURE1);, el sombreador vuelve a funcionar y aparece la misma textura en sampler0 y sampler1.

¿Qué está pasando? La línea en cuestión, glActiveTexture(GL_TEXTURE1);, parece funcionar bien, como lo demuestra un glGetIntegerv(GL_ACTIVE_TEXTURE, &anint) posterior. ¿Por qué rompe todo tan horriblemente? Ya he intentado actualizar mis controladores de pantalla.

+0

¿Has encontrado la solución a tu problema? Tengo exactamente el mismo problema. – Andrea3000

+0

Sí, la solución etiquetada funcionó para mí. – appas

Respuesta

24

Aquí hay un ejemplo básico de GLUT (escrito en OS X, se adapta según sea necesario) que genera dos texturas de tablero de ajedrez, carga un sombreador con dos muestreadores y los combina teñiendo cada uno (uno rojo, uno azul) y mezclando. A ver si esto funciona para usted:

#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; 
} 

Esperemos que el resultado se verá algo como esto (se puede comentar la llamada glUseProgram para ver la primera textura elaborado sin el shader): respuesta alt text

+0

Ok, esto funciona. Muchas gracias, ahora tengo una base de trabajo para tratar de resolver el problema en mi propio programa. – appas

+1

¿Por qué los uniformes dentro del sombreador se llaman "tex0, tex1", pero al llamar a "glGetUniformLocation" se llaman "tex1, tex2"? – Chris

+1

Una pregunta mejor podría ser: ¿cómo es que esto funciona, a pesar de que la ubicación de devolución de uno de los uniformes es "-1"? He probado el ajuste de los nombres de los uniformes a cualquier cadena y seguirá funcionando. ¿Alguien podría explicar esto, por favor? – Chris

0

Parece que su llamada glActiveTexture no funciona. ¿Estás seguro de que configuraste el puntero de función correctamente?

Verificar llamando al glGetIntegerv(GL_ACTIVE_TEXTURE, &anint) después de haber llamado a su glActiveTexture (GL_TEXTURE1).

También glEnable(GL_TEXTURE_2D) no son útiles. El sombreador mismo especifica qué unidades de textura usar, y qué objetivo de cada unidad "habilitar".


Editar para añadir:

Bueno, su nueva situación es peculiar. El hecho de que no puedas mostrar el rojo es extraño, en particular (bueno, ¿estableciste alfa a 1 solo para asegurarte?).

Dicho esto, debe restaurar GL_TEXTURE0 como glActiveTexture después de que haya terminado de configurar la unidad de textura 1 (es decir, después de la llamada glBindTexture).

+0

¿Tal vez está mezclando enumeraciones de la extensión ARB con funcionalidad central (la función)? Extraño de hecho. –

+1

Gracias por su pronta respuesta. Tenías razón: GL_ACTIVE_TEXTURE no estaba configurado correctamente. Ahora he arreglado el puntero a la función y el valor cambia como debería, pero ahora, todo lo que obtengo es negro. He actualizado la pregunta con mi nueva situación. – appas

+0

@Mads Elvheim: aclaró la última oración. – Bahbar

2

Al compilar su shader para probar, I encontraron dos errores:

  1. coords debe asignar la porción st de la 4-componente gl_TexCoord, por ejemplo

    vec2 coords = gl_TexCoord[0].st; 
    
  2. El sombreador no debe terminar con un punto y coma.

¿Está consultando en algún lugar de su programa principal que el sombreador se compila correctamente? Es posible que desee consultar GL_COMPILE_STATUS a través de glGetShader y glGetShaderInfoLog.

+0

Ok, bueno cambié la tarea pero no tuvo ningún efecto. El punto y coma era un error tipográfico, por lo que lo eliminé del mensaje original. Ya compruebo contra 'GL_COMPILE_STATUS', y el sombreador compila y enlaza correctamente en todos los casos, pero solo funciona realmente si dejo fuera la línea' glActiveTexture (GL_TEXTURE1); '- incluso si reemplazo todo con un oneliner que solo salidas blancas – appas

8

bastante tarde, pero para cualquiera que se encuentre con esto, me encontré con el mismo problema y después de un pequeño toque, me di cuenta de que llamar al glActiveTexture(GL_TEXTURE0) soluciona el problema. Parece que algo en el futuro se confunde si la unidad de textura activa no se "restablece" a cero. Esto podría comportamiento dependiente del sistema; Estoy ejecutando Archlinux de 64 bits con Mesa 8.0.4.

+0

Esto solucionó un extraño problema relacionado que estaba teniendo también. Muy bizarro –

+0

¡Un protector de vida absoluto! Revisé mi código, deconstruyéndolo hasta que estuve cruzado y buscando en docs y en línea, y no pude encontrar un solo error. Te hubiera votado x 100 si pudiera, John: ^) (win7 64bit GTX780) – yapdog

10

Solo para ayudar a otras personas que puedan estar interesadas en utilizar múltiples texturas y se sentirán sin esperanza después de días buscando una respuesta. He descubierto que es necesario llamar a

glUseProgram(program); 

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

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

En ese orden para que funcione (glUseProgram es la última instrucción para el 99% del código de ejemplo que he encontrado en Internet). Ahora puede ser solo el caso para mí y no afectar a nadie más en la Tierra, pero solo en caso de que yo pensara compartirlo.

+1

correcto, la página del manual dice "glUniform opera en el objeto del programa que formaba parte del estado actual al llamar a glUseProgram()" –

+0

esto no funcionó para mí (en OpenGL 2.0/GLSL 1.2), pero glGetUniformLocation/glUseProgram/glUniform1i lo hizo - http://stackoverflow.com/a/25252981/236081 – d3vid