¿Cuál es el mejor método para actualizar los uniformes de sombreadores?

10

¿Cuál es la forma más aceptada para mantener actualizadas las matrices de sombreadores y por qué?

Por ejemplo, en este momento tengo una Shaderclase que almacena los mangos para el programa de sombreado GLSL y uniformes. Cada vez que muevo la cámara, tengo que pasar la nueva matriz de visualización al sombreador, luego, cada objeto del mundo diferente debo pasar su matriz modelo al sombreador.

Esto me limita mucho, ya que no puedo hacer nada sin tener acceso a ese objeto sombreador.

Pensé en crear una ShaderManagerclase singleton que sea responsable de mantener todos los sombreadores activos. Entonces puedo acceder a eso desde cualquier lugar y un objeto mundial no tendría que saber qué sombreadores están activos solo que necesita informar a las ShaderManagermatrices deseadas, pero no estoy seguro de que esta sea la mejor manera y probablemente haya algunos problemas que surgirá de adoptar este enfoque.

Lerp
fuente
¿Por qué no pasar los datos a los sombreadores cuando llega el momento de renderizar?
Nick Caplinger
Eso es lo que pretendo pero ¿cómo? Si un objeto crea un sombreador, ¿cómo se supone que los objetos del mundo deben saber sobre la existencia de ese sombreador y pasarle las matrices necesarias?
Lerp

Respuestas:

11

Utilice tampones uniformes (es decir, tampones constantes en la jerga D3D).

Siempre y cuando todos sus sombreadores estén de acuerdo con el diseño y el punto de enlace de cada búfer, la actualización se convierte en una brisa. Las modelos no necesitan saber nada sobre sombreadores. Solo necesitan actualizar la matriz de vista de modelo en su búfer constante y la canalización de representación la usará automáticamente.

Como mínimo, diría que deberías tener dos de esos amortiguadores. El primero debe almacenar su matriz de proyección, la matriz de la cámara, la matriz de proyección de la cámara concatenada, la información de la vista, los detalles de frustrum y los inversos de la matriz. Solo necesita actualizar este búfer una vez por escena.

Luego, dé a cada modelo otro búfer para almacenar su matriz de vista de modelo, matriz normal, inversas y propiedades de material. Esto se actualiza una vez para cada modelo y se puede hacer en un pase de actualización diferente (si es apropiado). La información del material puede / debe moverse a un tercer búfer específico del material si tiene la capacidad de compartir materiales entre varios objetos.

En una configuración de sombreado hacia adelante, tiene sentido colocar todas las luces en otro búfer y, en el sombreado diferido, también tiene sentido usar un búfer por luz para el pase de luz (en lugar de un búfer modelo / material utilizado en el pase de geometría).

Tenga en cuenta que necesita una versión moderadamente actualizada de GL para usar buffers uniformes (3.1 o una extensión; lo suficientemente común hoy, excepto en algunas computadoras portátiles más antiguas pero aún en servicio) y necesita una versión bastante reciente para ser capaz de enlazar buffers uniformes a ubicaciones de enlace específicas desde el interior del código del sombreador (4.2; todavía es poco común pero está mejorando) de lo contrario, debe hacer más trabajo en el código del lado de la CPU para configurar las cosas (el código de la CPU necesita conocer el enlace correcto puntos de todos modos, por lo que es más un olor API que un problema grave). OpenGL | ES no agregó buffers uniformes hasta 3.0, que todavía no se admite en las plataformas móviles más populares, desafortunadamente.

Si los búferes no son una opción, necesitará un lugar global para almacenar ubicaciones de índice para el sombreador activo. Puede usar glGetUniformLocationdespués de cargar su sombreador para encontrar los índices de nombres conocidos (similares ModelViewMatrixo similares) y luego almacenar estos índices. Su render puede asignar valores de enumeración como MODEL_VIEWpasados ​​a una SetUniformfunción de contenedor para buscar en el sombreador enlazado, encontrar el índice y llamar glUniformcorrectamente. No se trata de un gran cambio en particular en el uso del código del cliente de los buffers que no sean la necesidad de configurar cada uniforme individualmente si lo envuelve todo bien.

Consulte Bloques de interfaz GLSL y Objetos de búfer uniformes .

Sean Middleditch
fuente
Sabía que sería una forma integrada. ¡Gracias!
Lerp
4

La forma más sencilla de hacerlo es estandarizar nombres uniformes entre los sombreadores y enviar todos los datos justo antes de dibujar. La sobrecarga no es una locura, pero puede optimizarla más adelante para no enviar siempre uniformes menos actualizados.

La forma en que hago esto en mi juego es que tengo una Materialclase abstracta . Los materiales actúan como un puente entre el juego y los sombreadores. Cada uno Materialtiene una Shadery varias propiedades que se pueden configurar, incluidas las texturas. Cuando es hora de dibujar un objeto, Materialestá obligado. El Bindmétodo tiene un GraphicsStateparámetro que contiene todos los estados gráficos actuales: matrices, luces, etc. El Bindmétodo une el sombreador y las texturas y establece todos los uniformes, usando lo que necesite del GraphicsState.

Robert Rouhani
fuente