¿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 Shader
clase 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 ShaderManager
clase 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 ShaderManager
matrices deseadas, pero no estoy seguro de que esta sea la mejor manera y probablemente haya algunos problemas que surgirá de adoptar este enfoque.
Respuestas:
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
glGetUniformLocation
después de cargar su sombreador para encontrar los índices de nombres conocidos (similaresModelViewMatrix
o similares) y luego almacenar estos índices. Su render puede asignar valores de enumeración comoMODEL_VIEW
pasados a unaSetUniform
función de contenedor para buscar en el sombreador enlazado, encontrar el índice y llamarglUniform
correctamente. 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 .
fuente
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
Material
clase abstracta . Los materiales actúan como un puente entre el juego y los sombreadores. Cada unoMaterial
tiene unaShader
y varias propiedades que se pueden configurar, incluidas las texturas. Cuando es hora de dibujar un objeto,Material
está obligado. ElBind
método tiene unGraphicsState
parámetro que contiene todos los estados gráficos actuales: matrices, luces, etc. ElBind
método une el sombreador y las texturas y establece todos los uniformes, usando lo que necesite delGraphicsState
.fuente