Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Unir varios shaders (sources) a un mismo programa

Iniciado por PIM, 29 de Junio de 2014, 04:59:04 AM

« anterior - próximo »

PIM

Hola queridos amigos de esta estupenda web. Pues eso, tengo la duda de cómo se pueden unir varios shaders a un mismo programa. Normalmente cuando un vertex shader y un fragment shader se unen a un programa; se hace algo como esto:

  vertex   = glCreateShader(GL_VERTEX_SHADER);
  fragment = glCreateShader(GL_FRAGMENT_SHADER);
  programa = glCreateProgram();

  char *vsFuente = LEE_SHADER(rutaVert);
  char *fsFuente = LEE_SHADER(rutaFrag);

  if(vsFuente == NULL)return GL_FALSE;
  if(fsFuente == NULL)return GL_FALSE;

  const char *vs = vsFuente;
  const char *fs = fsFuente;

  glShaderSource(vertex  ,1,&vs,NULL);
  glShaderSource(fragment,1,&fs,NULL);

  delete [] vsFuente;
  delete [] fsFuente;

  glCompileShader(vertex);
  glCompileShader(fragment);

  glAttachShader(programa,vertex);
  glAttachShader(programa,fragment);

  glLinkProgram(programa);


Bueno, pero si quiero unir otro par de shaders (vertex y fragment); en este caso a programa...   ¿Cómo debo hacerlo?

Muchas gracias por su ayuda.
;)

Gallo

Este es un pequeño error muy común (la manera en como has implementado la creación de un programa) de cuando se empieza con los shaders y se hace el tipico manager, normalmente por como lo explican los tutoriales incluso libros.  Un program puede estar compuesto por N shaders de diferentes tipos, pero siempre que lo explican parece que tengan que ser parejas de vertex y fragment y el código siempre se estructura de esa manera, con lo cual a veces no queda claro exactamente que es lo que se está haciendo realmente con un shader source.

Como veras en tu código tanto con el vertex shader como con el fragment shader estas haciendo exactamente lo mismo, ejecutas las mismas funciones de OpenGL para ambos, solo cambias dos parámetros: el tipo de shader y el puntero a su fuente, con lo cual lo mas correcto seria hacer una función a la que le pasas como parámetro un puntero al código o un path al fichero con el código del shader,  y otro parámetro que seria el tipo (vertex, fragment, geometry, etc..), y ejecutes todas esas funciones solo para un shadersource, devolviendo finalmente el name de ese shader (el resultado de glCreateShader) y haciendo glAttachShader de cada uno de ellos.



unsigned int createShaderSource(char const * path, GLenum type)
{
    unsigned int shaderName = glCreateShader(type);

    char *fuente = LEE_SHADER(path);

    if(fuente == NULL)
    {
        //error
    }

    const char *shaderSrc = fuente;

    glShaderSource(shaderName, 1, &shaderSrc, NULL);

    delete [] fuente;

    glCompileShader(shaderName);

    return shaderName;
}


struct ShaderSourceInfo
{
    const char* path;
    GLenum type;
};

//este array podria ser dinámico, un std::vector<ShaderSourceInfo> por ejemplo
ShaderSourceInfo shaderSourcesInfo[4] =
{
    {"vertex1.vs", GL_VERTEX_SHADER},
    {"vertex2.vs", GL_VERTEX_SHADER},
    {"fragment1.fs", GL_FRAGMENT_SHADER},
    {"fragment2.fs", GL_FRAGMENT_SHADER}
};

unsigned int programa = glCreateProgram();

for(int i = 0; i < 4; ++i) 
{
    unsigned int shaderName = createShaderSource[shaderSources[i].path, shaderSources[i].type);
    glAttachShader(programa, shaderName);
}

glLinkProgram(programa);


Y ya está, por supuesto solo puede haber un main() para vertex un main() para fragment, los otros solo pueden ser colecciones de funciones. Si tu intención es hacer un multipass en el que primero renderizas con un shader y luego el mismo objeto con otro, entonces va por otros derroteros, deberias hacer varis programs y renderizar el objeto varias veces.

PIM

Ok, amigo. Muchas gracias por tu estupenda explicación, ahora lo tengo más claro.

Saludos.
:D






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.