Cómo diseñar un contenedor GLSL simple para uso de sombreadores

ACTUALIZACIÓN: porque necesitaba algo de inmediato, he creado un envoltorio de sombreador simple que hace el tipo de cosas que necesito. Puedes encontrarlo aquí: ShaderManager en GitHub . Tenga en count que está diseñado para Objective-C / iOS, por lo que puede no ser útil para todos. Si tiene alguna sugerencia para mejoras de layout, ¡hágamelo saber!

Problema original:

Soy nuevo en el uso de sombreadores GLSL. Ya soy bastante familiar con el lenguaje GLSL y la interfaz OpenGL, pero tengo problemas para diseñar una API simple a través de la cual usar sombreadores.

La interfaz C de OpenGL para interactuar con shaders parece engorrosa. No puedo encontrar ningún tutorial en la networking que cubra el layout API de tales cosas.

Mi pregunta es esta: ¿alguien tiene un layout o patrón de API simple y bueno para envolver la API del progtwig sombreador OpenGL?

Tomemos el siguiente ejemplo simple. Digo que tengo un sombreador de vértices que simplemente emula la funcionalidad fija, y dos sombreadores de fragment, uno para dibujar rectangularjs suaves y otro para dibujar círculos suaves. Tengo los siguientes files:

Shader.vsh : Simple vertex shader, with the following inputs/outputs: -- Uniforms: mat4 Model, mat4 View, mat4 Projection -- Attributes: vec4 Vertex, vec2 TexCoord, vec4 Color -- Varying: vec4 vColor, vec2 vTexCoord Square.fsh : Fragment shader for drawing squares based on tex coord / color Circle.fsh : Fragment shader for drawing circles based on tex coord / color 

Vinculación básica

Ahora, ¿cuál es la forma estándar de usarlos? ¿Enloop los sombreadores anteriores en dos progtwigs de sombreador OpenGL? Es decir:

 Shader.vsh + Square.fsh = SquareProgram Shader.vsh + Circle.fsh = CircleProgram 

O, en cambio, creo un gran progtwig donde los sombreadores de fragments comtestingn algunas variables uniformes condicionales y llaman a una function de sombreador para generar su resultado. P.ej:

 Shader.vsh + Square.fsh + Circle.fsh + Main.fsh = ShaderProgram //Main.fsh here would simply check whether to call out to square or circle 

Con dos progtwigs individuales, presumiblemente tendría que llamar

 glUseProgram(CircleProgram); or glUseProgram(SquareProgram); 

Antes de cada tipo de elemento que quiero dibujar. Entonces tendría que configurar los uniformes (model / vista / proyección) y los attributes de cada progtwig antes de usarlo. Esto parece tan difícil de manejar.

Con la única opción de ShaderProgram, necesitaría establecer algún tipo de conmutador boolean (círculo o cuadrado) en el fragment sombreador que se verificará antes de dibujar cada píxel. Esto también parece complicado.

Como nota al margen, ¿puedo vincular dos sombreadores de fragment, cada uno con una function principal (), en un progtwig de sombreador? ¿Cómo sabría OpenGL a cuál llamar?

Configuración de variables

Las llamadas:

 glUniform* glVertexAttribPointer 

Se utilizan para configurar uniformes y asignar ubicaciones de puntero en el progtwig actual.

Pueden ser necesarias diferentes classs y estructuras para acceder y establecer variables en el sombreador actual (o cambiar el sombreador actual) desde diferentes lugares del código. No puedo pensar en una buena forma de hacer esto que desacopla el código del sombreador del código que quiere usarlo.

Es decir, cada forma que desee dibujar necesitará establecer los attributes de coorderadas de vértices y texturas, lo que requiere que los manejadores tengan los attributes generados por OpenGL.

La camera deberá configurar su matriz de proyección como un uniforme en el sombreador de vértices, mientras que la class que gestione la stack de matriz model tendrá que establecer su propio uniforme en el sombreador de vértices.

Cambiar los sombreadores parcialmente durante el dibujo de una escena significaría que todas estas classs necesitarán establecer sus uniformes y attributes nuevamente.

¿Cómo se diseña la mayoría de las personas en torno a esto?

¿Un dictionary global de sombreadores al que se accede mediante identificador o nombre, con getters y setters para sus parameters?

¿Un layout de OO con objects de sombreador que tienen parameters cada uno?

He mirado los siguientes contenedores:

Tetera de Jon: GLSL Shader Manager – Esto envuelve los sombreadores en classs de C ++. Parece poco más que un contenedor que impone los principios OO en una API C, lo que resulta en una API C ++ que es muy similar.

Estoy buscando cualquier tipo de layout que simplifique el uso de los progtwigs de Shader, y no me preocupa el paradigma particular utilizado (OO, procedimiento, etc.)

    Enlace básico:

    No hay una forma estándar aquí. Hay al less 2 enfoques generales:

    1. Monolítico: un sombreador cubre muchos casos, utilizando interruptores booleans uniformes. Estas twigs no dañan el performance porque el resultado de la condición es constante para cualquier grupo de fragments (en realidad, para todos los fragments).

    2. Composition de progtwigs multiobjects: el sombreador principal declara un set de puntos de input (como 'get_diffuse', 'get_specular', etc.), que se implementan en objects de sombreado separados adjuntos. Esto implica un sombreador individual para cada object, pero cualquier tipo de caching ayuda.

    Configuración de variables: uniformes

    Simplemente describiré el enfoque que desarrollé.

    Cada progtwig de sombreado tiene una list de dictionarys uniformes. Se utiliza para completar la list de fonts uniforme en el progtwig (re) vinculación. Cuando el progtwig está activado, pasa por la list de uniformes, obtiene valores de sus fonts y los carga a GL. En el resultado, los datos no están conectados directamente con el progtwig de sombreador de usuario, y cualquier cosa que gestione no le importa el progtwig que lo usa.

    Uno de estos dictionarys puede ser, por ejemplo, uno central, que contenga el model, las transformaciones de la vista, la proyección de la camera y tal vez otra cosa.

    Configurar variables: attributes

    En primer lugar, el progtwig shader es un consumidor de attributes, por lo que es lo que tiene que extraer estos attributes de una malla (o cualquier otro almacenamiento de datos) y cargarlos a GL de la manera que necesita. También debe asegurarse de que los types de attributes proporcionados coincidan con los types solicitados.

    Cuando se usa con un enfoque de sombreado monolítico, existe una posible situación desagradable cuando una de las vías de la twig desactivada requiere un atributo de vértice que no se proporciona. Le aconsejaría usar los datos de otro atributo para suministrar el faltante, porque no nos importan los valores reales en este caso.

    PS Puede encontrar una implementación real de estas ideas aquí: http://code.google.com/p/kri/

    Veo que esto está labeldo con iOS, así que si eres parcial con Objective-C, echaré un vistazo a la class de envoltura de GLProgram de Jeff LaMarche, que él describe aquí y tiene una fuente disponible aquí . Lo he usado dentro de mis propias aplicaciones para simplificar algo de la configuration del progtwig de sombreador, y para hacer que el código sea un poco más limpio.

    Por ejemplo, puede configurar un sombreador y sus attributes y uniformes utilizando un código como el siguiente:

     sphereDepthProgram = [[GLProgram alloc] initWithVertexShaderFilename:@"SphereDepth" fragmentShaderFilename:@"SphereDepth"]; [sphereDepthProgram addAttribute:@"position"]; [sphereDepthProgram addAttribute:@"inputImpostorSpaceCoordinate"]; if (![sphereDepthProgram link]) { NSLog(@"Depth shader link failed"); NSString *progLog = [sphereDepthProgram programLog]; NSLog(@"Program Log: %@", progLog); NSString *fragLog = [sphereDepthProgram fragmentShaderLog]; NSLog(@"Frag Log: %@", fragLog); NSString *vertLog = [sphereDepthProgram vertexShaderLog]; NSLog(@"Vert Log: %@", vertLog); [sphereDepthProgram release]; sphereDepthProgram = nil; } sphereDepthPositionAttribute = [sphereDepthProgram attributeIndex:@"position"]; sphereDepthImpostorSpaceAttribute = [sphereDepthProgram attributeIndex:@"inputImpostorSpaceCoordinate"]; sphereDepthModelViewMatrix = [sphereDepthProgram uniformIndex:@"modelViewProjMatrix"]; sphereDepthRadius = [sphereDepthProgram uniformIndex:@"sphereRadius"]; 

    Cuando necesite usar el progtwig de sombreado, entonces haga algo como lo siguiente:

     [sphereDepthProgram use]; 

    Esto no aborda los problemas de bifurcación versus sombreadores individuales que se mencionan anteriormente, pero la implementación de Jeff proporciona una bonita encapsulación de algunos de los códigos de configuration de sombreador de boilerplate de OpenGL ES.