Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Error al compilar objeto de shader

Iniciado por killgates, 05 de Diciembre de 2015, 06:43:33 PM

« anterior - próximo »

killgates

Hola,

Tengo un problema al compilar un objeto de shader. Pues me devuelve FALSE cuando compruebo el estado de la compilación. El código es el siguiente:
         
         //fuenteShader es un arreglo de 1000 índices de tipo char que contiene el fichero de shader todo seguido.
    const GLchar* tmp = static_cast<const GLchar*>(fuenteShader);  //Esta parte la he sacado de un libro de opengl con c++
    glShaderSource(objetoShader1, 1, (const GLchar**)&tmp, NULL);  //Si me la podeis explicar Gracias

    glCompileShader(objetoShader1);
    GLint result;
    glGetShaderiv(objetoShader1, GL_COMPILE_STATUS, &result);
    if (result == GL_TRUE)
        std::cout << "\nEl shader se compiló con éxito";
    else std::cout << "\nEl shader no se ha compilado con exito!";


Siempre me dice que el shader no se ha compilado con éxito.
Gracias.

Gallo

Como el error puede ser debido a muchos motivos, desde que no estés pasando el tipo de shader correcto a cualquier error de sintaxis, te recomiendo agregar esto a la comprobación de errores:



      //fuenteShader es un arreglo de 1000 índices de tipo char que contiene el fichero de shader todo seguido.
    const GLchar* tmp = static_cast<const GLchar*>(fuenteShader);  //Esta parte la he sacado de un libro de opengl con c++
    glShaderSource(objetoShader1, 1, (const GLchar**)&tmp, NULL);  //Si me la podeis explicar Gracias

    glCompileShader(objetoShader1);
    GLint result;
    glGetShaderiv(objetoShader1, GL_COMPILE_STATUS, &result);

    if (result == GL_TRUE)
    {
        std::cout << "El shader se compiló con éxito" << std::endl;
    }
    else
    {
    GLchar log[1024];
        GLsizei logLen;
        glGetShaderInfoLog(objetoShader1, sizeof(GLchar)*1024, &logLen, log);
        std::cout << "El shader no se ha compilado con exito!" << std::endl;
        std::cout << "ShaderInfoLog: " << log << std::endl;
    }

killgates

Hola,
He añadido lo que me has puesto en el else y ha quedado así:

    else {
        //!**********************
        GLchar log[1024];
        GLsizei logLen;
        glGetShaderInfoLog(objetoShader1, sizeof(GLchar)*1024, &logLen, log);
        std::cout << "El shader no se ha compilado con exito!" << std::endl;
        std::cout << "ShaderInfoLog: " << log << std::endl;
        //!****************************************************
    }


Me sigue devolviendo lo mismo. Seguido de "ShaderInfoLog" y en blanco.

Gracias

[Fonet]

Buenas, no tengo ni idea de shaders y probablemente lo que voy a decir sea una tontería como una casa pero ¿no tendrías que pasar la variable log como referencia?

glGetShaderInfoLog(................................., &log)

Saludos!

Gallo

Cita de: [Fonet] en 09 de Diciembre de 2015, 05:50:06 PM
Buenas, no tengo ni idea de shaders y probablemente lo que voy a decir sea una tontería como una casa pero ¿no tendrías que pasar la variable log como referencia?

glGetShaderInfoLog(................................., &log)

Saludos!

log ya es un puntero a char, es lo que espera la función y a mi este log me escupe los errores en el shader perfectamente, que raro que salga en blanco, el error debe estar en otro sitio. Al glGetShaderInfoLog le estas pasando el tipo correcto y tal no? que veo que no lo has puesto.

killgates

Hola,

La función glgetshaderinfolog(); también me aparece en el libro. Aunque no entiendo su funcionamiento muy bien (soy un poco novato todavía).
Mejor pongo el código completo que tengo puesto en la etapa de compilación... :


    char fuenteShader[500];
    char fuenteFragmentShader[500];
    GLuint objetoShader1;
    GLuint objetoShader2;
    GLuint programaShader;

void glsl::compila(){
        objetoShader1 = glCreateShader(GL_VERTEX_SHADER);        //!Esto crea los objetos de shader (2) y el objeto de programa
        objetoShader2 = glCreateShader(GL_FRAGMENT_SHADER);
        programaShader = glCreateProgram();

    //!--------------- Primer objeto ---------------
        //!Aquí guardo en los objetos el codigo
    const GLchar* tmp = static_cast<const GLchar*>(fuenteShader);
    glShaderSource(objetoShader1, 1, &tmp, NULL);

        //!Y aquí compilo..
    glCompileShader(objetoShader1);
    GLint result;
    glGetShaderiv(objetoShader1, GL_COMPILE_STATUS, &result);
    if (result == 1)
        std::cout << "\nEl vertex shader se compiló con éxito";
    else {

        //!**********************
        GLchar log[1024];
        GLsizei logLen;
        glGetShaderInfoLog(objetoShader1, sizeof(GLchar)*1024, &logLen, log);
        std::cout << "El vertex shader no se ha compilado con exito!" << std::endl;
        std::cout << "ShaderInfoLog: " << log << std::endl;
        //!****************************************************
    }
    //!---------------- segundo objeto --------------
    const GLchar* tmp2 = static_cast<const GLchar*>(fuenteFragmentShader);
    glShaderSource(objetoShader2, 1, (const GLchar**)&tmp2, NULL);
        //!Y aquí compilo..
    glCompileShader(objetoShader2);
    glGetShaderiv(objetoShader2, GL_COMPILE_STATUS, &result);
    if (result == 1)
        std::cout << "\nEl fragment shader se compiló con éxito";
    else {

        //!********************** sacado de un foro de internet
        GLchar log[1024];
        GLsizei logLen;
        glGetShaderInfoLog(objetoShader1, sizeof(GLchar)*1024, &logLen, log);
        std::cout << "El fragment shader no se ha compilado con exito!" << std::endl;
        std::cout << "ShaderInfoLog: " << log << std::endl;
        //!****************************************************
    }
    //! Esto añade los shaders ya compilados al objeto de programa
    glAttachShader(programaShader, objetoShader1);
    glAttachShader(programaShader, objetoShader2);
    //! Y esto vincula el programa
    glLinkProgram(programaShader);
    //! Y esto comprueba la vinculación
    glGetProgramiv(programaShader, GL_LINK_STATUS, &result);
    if (result == GL_TRUE){
        std::cout << "\nEl programa de shaders se ha vinculado con exito!";
    }
    else std::cout << "\nEl programa de shader no se ha vinculado con exito!";
    glGetProgramiv(programaShader, GL_ATTACHED_SHADERS, &result);
    std::cout << "\nSe han aduntado " << result << " numeros de shader al programa";
    }


los arreglos "fuenteshader" y "fuentefragmentShader" contienen el código de los shaders. En una sóla cadena.
Los leo a través de getc(fichero).

Gracias


Ray

glShaderSource lo que hace es reemplazar el código en un objeto ya creado, pero antes tienes que crearlo con glCreateShader





killgates

Hola,

Ya creo el objeto de shader con glcreateshader() al principio de la función glsl::compila()

Me parece que eso lo hago bien

Gallo

Si de hecho en mi comentario anterior me equivoqué me refería a glCreateShader y el copy paste me la jugó, estas llamando a glCreateShader con el tipo correcto no? También estamos seguros de que el código fuente está correctamente guardado en esa variable y tal no? Es muy raro. Lo último es que tu tarjeta gráfica soporte la versión de OpenGL donde son compatibles por primera vez estas funciones.

Ray

¿pero qué hay en "fuenteShader"?, ¿estás cargando algo?




killgates

Hola,

En fuenteshader está el código sin compilar de los shaders. Que se cargan en la memora de la gpu.

Y esto no lo acabo de entender (lo he sacado de un libro):

    const GLchar* tmp = static_cast<const GLchar*>(fuenteShader);
    glShaderSource(objetoShader1, 1, &tmp, NULL);

Lo que interpreto es que creo una variable puntero de tipo GLchar llamada "tmp". (const no lo utilizo nunca)
Y le asigno la dirección del arreglo fuenteshader (que es donde está el código). Lo de "static_cast<const GLchar*>( )" tampoco lo entiendo muy bien. Si me lo podeis explicarj, gracias. Lo he sacado de un libro.

Y también por qué no puedo hacer:

glShaderSource(objetoShader1, 1, &fuenteshader, NULL);


No puede estar ahí el error?
Gracias a todos

Ray

#11
es que no se ve que cargues ningún código en ese array, o no se sabe lo que contiene porque puede ser algún error de compilación.

te pongo un ejemplo de shader simple que está sacado del opengl superbible, se crea en una función sin nada más, esta función devuelve el programa que luego se usará

GLuint compile_shaders(void)
{
GLuint vertex_shader;
GLuint fragment_shader;
GLuint program;

/*
aquí el código se carga directamente pero también se puede cargar de un archivo de texto de manera normal
lo que hace este vertex shader es dibujar un triángulo enviando la posición de cada vértice que le llegue para ser dibujado,
como en este caso no se le va a pasar ningún  vértice lo que hará es pasar el vertice del vector que se define en el propio shader,
basta con que el shader sepa qué número de vertice es, que le viene indicado en gl_VertexID */

static const GLchar * vertex_shader_source[] =
{
"void main(void) \n"
"{ \n"
" const vec4 vertices[3] = vec4[3](vec4(0.25, -0.25, 0.5, 1.0), \n"
" vec4(-0.25, -0.25, 0.5, 1.0), \n"
" vec4(0.25, 0.25, 0.5, 1.0)); \n"
" gl_Position = vertices[gl_VertexID]; \n"
"} \n"
};

// el fragment shader simplemente coge todos los vértices que le lleguen y los pinta del color que está definido en un vector

static const GLchar * fragment_shader_source[] =
{
"out vec4 color; \n"
" \n"
"void main(void) \n"
"{ \n"
" color = vec4(0.0, 0.8, 1.0, 1.0); \n"
"} \n"
};

// esto es lo típico, se crea el shader, se le carga el código, y se compila.

// Create and compile vertex shader
vertex_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_shader, 1, vertex_shader_source, NULL);
glCompileShader(vertex_shader);

// Create and compile fragment shader
fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment_shader, 1, fragment_shader_source, NULL);
glCompileShader(fragment_shader);

// luego ya se crea el programa, se asigna los shader y se enlaza, listo para ser ejecutado
// Create program, attach shaders to it, and link it
program = glCreateProgram();
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
glLinkProgram(program);

// los shader se puede borrar porque ya se cargaron en el programa
// Delete the shaders as the program has them now
glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);

return program;
}



para usarlo es muy simple, primero se carga el programa

   rendering_program = compile_shaders();

y para ejecutar el shader, basta con activar el programa de shader que vamos a usar
   
   glUseProgram(rendering_program);

y dibujar los triángulos, (que en este caso solo va a dibujar uno porque se le pasan 3 vértices)
   glDrawArrays(GL_TRIANGLES, 0, 3);


una vez que tienes esto podrías modificar el shader para que dibuje por ejemplo una tira de triángulos con 20 vértices mediante un bucle, y mandando la función de dibujo correspondiente.

   glDrawArrays(GL_TRIANGLE_STRIP, 0, 20);


killgates

Hola,

Perdón. Ahora pongo la función que lee un fichero del disco (el shader) y lo guarda en un arreglo unidimensional normal, para luego pasarlo al objeto de shader.

Antes pongo la función que abre ficheros.. :      (lo estoy haciendo todo separado en funciones dentro de una clase "glsl")


    void glsl::OpenFiles(){
        if ((fichero=fopen(nombreFicheroShader, "r"))==NULL){
            std::cout << "no se ha podido abrir el fichero: " << nombreFicheroShader <<  ".. Pulse una tecla para salir\n";
            getchar();
            exit(1);
        }
        //else std::cout << "\nFichero Abierto con exito!";
        if ((fichero2=fopen(nombreFicheroFragmentShader, "r"))==NULL){
            std::cout << "no se ha podido abrir el fichero: " << nombreFicheroFragmentShader <<  ".. Pulse una tecla para salir\n";
            getchar();
            exit(1);
        }
    }


Y ahora, la función que lee los ficheros y los guarda en dos arreglos: "fuenteshader" y "fuenteshaderfragment"


    void glsl::leeFichero(){
        char caracter;
        int x = 0, y = 0;
        if ((fichero == NULL)||(fichero2 == NULL)){
            std::cout << "\nAlgun fichero no esta abierto!";
            return;
        }
        fseek(fichero, 0, SEEK_SET);  //!Hasta aquí abro el fichero y me coloco al principio
        //!Y leo todo el fichero y lo guardo en el arreglo fuenteShader de una dimensión
        do {
            caracter = getc(fichero);
            if (caracter == EOF){
                std::cout << "No hay nada en el fichero de shaders!, es decir, está en blanco!";
                return;
            }
        } while ((caracter == ' ')||(caracter == 13));
        for (int contador = 0; caracter != EOF; contador++){
            caracter = getc(fichero);
            fuenteShader[contador] = caracter;
        }
        //!******** Y hag lo mismo con el fichero de fragment shader ..:

                fseek(fichero2, 0, SEEK_SET);  //!Hasta aquí abro el fichero y me coloco al principio
        //!Y leo todo el fichero y lo guardo en el arreglo nombreFicheroFragmentShader[] de una dimensión
        do {
            caracter = getc(fichero2);
            if (caracter == EOF){
                std::cout << "No hay nada en el fichero de fragment shaders!, es decir, está en blanco!";
                return;
            }
        } while ((caracter == ' ')||(caracter == 13));
        for (int contador = 0; caracter != EOF; contador++){
            caracter = getc(fichero2);
            fuenteFragmentShader[contador] = caracter;
        }
        //!**** aquí acabo de leer los dos ficheros.. **
    }


Veo que tú generás el código de los shaders desde el programa. Yo los tomo de ficheros.
Si hago un "puts(fuenteshader);" me aparece el código del fichero shader leído.
Que es éste:


#version 130

uniform mat4 projection_matrix;
uniform mat4 modelview_matrix;

in vec3 a_Vertex;
in vec3 a_Color;
out vec4 color;

void main(void)
{
vec4 pos = modelview_matrix * vec4(a_Vertex, 1.0);
gl_Position = projection_matrix * pos;
color = vec4(a_Color, 1.0);
}



Y luego vendría el otro..:


#version 130

in vec4 color;
out vec4 outColor;

void main(void) {
outColor = color;
}



Esto está sacado de un libro que he comprado.
Gracias

Ray

puede ser porque esas cadenas de texto tienen que tener al final el null '0\' para que sepa donde termina.

killgates

#14
Hola,

Tengo una función dentro de la clase que pone a NULL todo el arreglo fuenteshader[] y fuenteshaderfragment[], que es lo que contiene el código del vertex y fragment shader. La llamo antes de rellenar los arreglos.

La verdad, no se que estoy haciendo mal. He repasado las funciones que leen los ficheros que contienen los shader y había el error que se comía el "#" del principio, y ya lo he arreglado. Pero sigue sin funcionar..

Gracias






Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
Muchísimas gracias.