opengl - texture - Múltiples texturas en GLSL: solo funciona una
texture in opengl c++ (5)
Al compilar tu sombreador para probar, encontré dos errores:
coords
se les debe asignar la parte más alta de los 4 componentesgl_TexCoord
, por ej.vec2 coords = gl_TexCoord[0].st;
El sombreador no debe terminar con un punto y coma.
¿Está consultando en algún lugar de su programa principal que el sombreador compila correctamente? Es posible que desee ver GL_COMPILE_STATUS
través de glGetShader
y glGetShaderInfoLog
.
Mi problema es obtener más de una textura accesible en un sombreador GLSL. Esto es lo que estoy haciendo:
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;
}
};
Entonces, simplemente elijo entre los dos valores de color basados en una variable uniforme. Lo suficientemente simple (esta es una prueba), pero en lugar del comportamiento esperado, me pongo todo negro cuando mezclo <= 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 sombreador está compilado y atado 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 la última Reparado de acuerdo con la respuesta de Bahbar. glBindTexture
para enlazar Texture0.Handle
, la textura cambia.
Tal 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 funciona nuevamente, y la misma textura aparece tanto en sampler0 como en sampler1.
¿Que esta pasando? La línea en cuestión, glActiveTexture(GL_TEXTURE1);
, parece funcionar muy bien, como se evidencia por una subsiguiente glGetIntegerv(GL_ACTIVE_TEXTURE, &anint)
. ¿Por qué rompe todo tan horriblemente? Ya he intentado actualizar mis controladores de pantalla.
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. Vea 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 vea más o menos así (puede comentar la llamada glUseProgram
para ver la primera textura dibujada sin el sombreador):
Parece que tu llamada glActiveTexture
no funciona. ¿Estás seguro de que configuraste el puntero de función correctamente?
Verifique llamando a 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 agregar:
Bueno, tu 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, debes restaurar GL_TEXTURE0 como glActiveTexture
después de que hayas terminado de configurar la unidad de textura 1 (es decir, después de la llamada glBindTexture
).
Respuesta bastante tardía, pero para cualquiera que se topa con esto, me encontré con el mismo problema y después de un pequeño cambio de sentido, me di cuenta de que llamar a 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 ser un comportamiento dependiente del sistema; Estoy ejecutando Archlinux de 64 bits con Mesa 8.0.4.
Solo para ayudar a otras personas que podrían estar interesadas en usar múltiples texturas y se sentirán sin esperanza después de días buscando una respuesta. Descubrí que debes llamar
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 muestra que he encontrado en línea). 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.