Uniformes

Les variables uniformes sont utilisées pour transmettre des données qui sont globales à un appel de rendu particulier et qui ne changent pas par sommet ou par fragment. Un vertex ou fragment shader peut recevoir des uniformes. Cela peut inclure des éléments tels que le temps écoulé, les matrices de transformation, les informations sur l’éclairage ou les propriétés des matériaux.

L’uniforme est déclarée dans un shader. Pour envoyer une valeur uniforme il faut trouver son emplacement dans la mémoire du GPU. Ensuite, la donnée peut être transmise. Les uniformes sont définies depuis l’application OpenGL et sont en immuables dans le shader.

//Vertex Shader
#version 460 core
layout (location = 0) in vec3 position;
uniform float offset; 

void main() {
    vec3 newPos = position + vec3(offset, 0.0, 0.0);
    gl_Position = vec4(newPos, 1);
}

Si la valeur uniforme ne change pas à travers le temps, il n’est pas nécessaire d’envoyer sa valeur à chaque itération de la boucle principale.

// ...
// déclarer et initialiser la constante
constexpr float xTranslation = 0.5f;

// ...

int main() {
  // ...

  // utiliser le programme de shader compilé
  glUseProgram(shaderProgram);     
  // obtenir l'emplacement en VRAM de la variable `offset` déclarée dans le vertex shader de shaderProgram
  GLint offsetLocation = glGetUniformLocation(shaderProgram, "offset");
  
  // transférer la valeur sur le GPU
  glUniform1f(offsetLocation, xTranslation);

  // ...
  // boucle du jeu
  // ...
}

Si la valeur change à chaque itération, il faut mettre à jour la mémoire du GPU.

// ...
// déclarer et initialiser la variable
float xTranslation = 0.5f;

// ...

int main() {
  // ...

  // obtenir l'emplacement en VRAM
  GLint offsetLocation= glGetUniformLocation(shaderProgram, "offset");

  while (!glfwWindowShouldClose(window)) {
    // ...

    // changement de l'uniforme; il faut mettre à jour la valeur sur le GPU
    xTranslation += 0.001f;
    // transférer la valeur sur le GPU
    glUniform1f(offsetLocation, xTranslation);
  }
}

Notez que nous ne sommes pas forcés dans une situation « tout ou rien ». Nous pouvons mettre à jour la valeur dans la VRAM à chaque \(n\) itérations, ou à chaque \(m\) secondes, si les données ne sont pas mise-à-jour fréquemment. Optimisation !