ShaderProgram Utility
Autor: KlanPaia | Publicado: 2013-02-02T23:17:00-08:00


ShaderProgram Utility
Este pagina demonstra &nbsp;passos necessários para se criar o sua própria classe re-utilizável&nbsp;através&nbsp;do utilitário ShaderProgram. Você também pode usar o mais avançado utilitário de ShaderProgram já incluído no LWJGL-básico: ver aqui.




Para nossos propósitos, vamos usar apenas um vértice e um fragmento de shader para criar os nossos programas de sombreamento. Planejamos visar o GL 2.1, que também terá de especificar os locais de atributos manualmente. Se for usar versões mais recentes do OpenGL (ou seja, GLSL 330 +), então podemos especificar os locais de atributos com qualificadores do tipo em seu lugar. Os passos básicos para a criação de um programa de shader como este são:



Compilar o código fonte em um vértice shader shader objeto.



Compilar o código fonte em um fragmento de shader shader objeto.



Criar um programa com ID glCreateProgram.



Anexar os objetos vertex e shader para o nosso programa com glAttachShader.

Se nós estamos usando 2.1, é aqui que ligaria quaisquer atributos manualmente. Por exemplo, poderíamos vincular o atributo posição de índice 0. Para isso, usamos glBindAttribLocation. Se nós estamos usando versões mais recentes do GLSL, podemos pular essa etapa.



Em seguida, ligar o programa com glLinkProgram.



Se o programa conseguiu compilar, agora podemos separar e excluir os objetos de sombreamento da vértice e fragmento como eles não são mais necessários - usando glDetachShader e glDeleteShader, respectivamente. Estes são apenas avisam para o OpenGL, que os objetos serão apagados quando eles não estão mais associados com quaisquer estados de renderização.



Exemplo:

public ShaderProgram(String vertexShader, String fragmentShader, Map&lt;Integer, String&gt; attributes) throws LWJGLException {
 //compile the String source
 vertex = compileShader(vertexShader, GL_VERTEX_SHADER);
 fragment = compileShader(fragmentShader, GL_FRAGMENT_SHADER);
 
 //create the program
 program = glCreateProgram();
 
 //attach the shaders
 glAttachShader(program, vertex);
 glAttachShader(program, fragment);

 //bind the attrib locations for GLSL 120
 if (attributes != null)
  for (Entry&lt;Integer, String&gt; e : attributes.entrySet())
   glBindAttribLocation(program, e.getKey(), e.getValue());

 //link our program
 glLinkProgram(program);

 //grab our info log
 String infoLog = glGetProgramInfoLog(program, glGetProgrami(program, GL_INFO_LOG_LENGTH));
 
 //if some log exists, append it 
 if (infoLog!=null &amp;&amp; infoLog.trim().length()!=0)
  log += infoLog;
 
 //if the link failed, throw some sort of exception
 if (glGetProgrami(program, GL_LINK_STATUS) == GL_FALSE)
  throw new LWJGLException(
    "Failure in linking program. Error log:\n" + infoLog);
 
 //detach and delete the shaders which are no longer needed
 glDetachShader(program, vertex);
 glDetachShader(program, fragment);
 glDeleteShader(vertex);
 glDeleteShader(fragment);
}

protected int compileShader(String source, int type) throws LWJGLException {
 //create a shader object
 int shader = glCreateShader(type);
 //pass the source string
 glShaderSource(shader, source);
 //compile the source
 glCompileShader(shader);

 //if info/warnings are found, append it to our shader log
 String infoLog = glGetShaderInfoLog(shader,
   glGetShaderi(shader, GL_INFO_LOG_LENGTH));
 if (infoLog!=null &amp;&amp; infoLog.trim().length()!=0)
  log += getName(type) +": "+infoLog + "\n";
 
 //if the compiling was unsuccessful, throw an exception
 if (glGetShaderi(shader, GL_COMPILE_STATUS) == GL_FALSE)
  throw new LWJGLException("Failure in compiling " + getName(type)
    + ". Error log:\n" + infoLog);

 return shader;
}


Usando o programa:


Em OpenGL, só podemos ter um programa único de shader em uso ao mesmo tempo. Chamamos glUseProgram (programa) para especificar o programa ativo. Devemos especificar o glUseProgram (0) para usar o "default" do shader. No entanto, uma vez que estamos tentando trabalhar com o pipeline programável, não devemos mais nos preocupar com o shader padrão, já que não existe tal coisa no GL moderna. Na verdade, ele pode causar erros se tentarmos renderização com o shader padrão no GL 3.1 + &nbsp;



Assim, nossos métodos para se criar um programa final ficará assim::




/**
 * Make this shader the active program.
 */
public void use() {
 glUseProgram(program);
}

/**
 * Destroy this shader program.
 */
public void destroy() {
 //a flag for GL -- the program will not actually be deleted until it's no longer in use
 glDeleteProgram(program);
}

/**
 * Gets the location of the specified uniform name.
 * @param str the name of the uniform
 * @return the location of the uniform in this program
 */
public int getUniformLocation(String str) {
 return glGetUniformLocation(program, str);
}



Definir valores uniformes:




Tal como discutido anteriormente na série, usamos glUniform para passar dados uniformes para os nossos shaders. Um utilitário ShaderProgram completa pode incluir diversos&nbsp;utilitários&nbsp;para obter e definir uniformes (veja aqui). Nosso exemplo simples irá lidar com o mínimo de: matrizes e uniformes inteiros (para sampler2D).




/**
 * Sets the uniform data at the specified location (the uniform type may be int, bool or sampler2D). 
 * @param loc the location of the int/bool/sampler2D uniform 
 * @param i the value to set
 */
public void setUniformi(int loc, int i) {
 if (loc==-1) return;
 glUniform1i(loc, i);
}

/**
 * Sends a 4x4 matrix to the shader program.
 * @param loc the location of the mat4 uniform
 * @param transposed whether the matrix should be transposed
 * @param mat the matrix to send
 */
public void setUniformMatrix(int loc, boolean transposed, Matrix4f mat) {
 if (loc==-1) return;
 if (buf16Pool == null)
  buf16Pool = BufferUtils.createFloatBuffer(16);
 buf16Pool.clear();
 mat.store(buf16Pool);
 buf16Pool.flip();
 glUniformMatrix4(loc, transposed, buf16Pool);
}


Código fonte completo:



public class ShaderProgram {

 protected static FloatBuffer buf16Pool;
 
 /**
  * Makes the "default shader" (0) the active program. In GL 3.1+ core profile,
  * you may run into glErrors if you try rendering with the default shader. 
  */
 public static void unbind() {
  glUseProgram(0);
 }

 public final int program;
 public final int vertex;
 public final int fragment;
 protected String log;

 public ShaderProgram(String vertexSource, String fragmentSource) throws LWJGLException {
  this(vertexSource, fragmentSource, null);
 }

 /**
  * Creates a new shader from vertex and fragment source, and with the given 
  * map of  attrib locations
  * @param vertexShader the vertex shader source string
  * @param fragmentShader the fragment shader source string
  * @param attributes a map of attrib locations for GLSL 120
  * @throws LWJGLException if the program could not be compiled and linked
  */
 public ShaderProgram(String vertexShader, String fragmentShader, Map&lt;Integer, String&gt; attributes) throws LWJGLException {
  //compile the String source
  vertex = compileShader(vertexShader, GL_VERTEX_SHADER);
  fragment = compileShader(fragmentShader, GL_FRAGMENT_SHADER);
  
  //create the program
  program = glCreateProgram();
  
  //attach the shaders
  glAttachShader(program, vertex);
  glAttachShader(program, fragment);

  //bind the attrib locations for GLSL 120
  if (attributes != null)
   for (Entry&lt;Integer, String&gt; e : attributes.entrySet())
    glBindAttribLocation(program, e.getKey(), e.getValue());

  //link our program
  glLinkProgram(program);

  //grab our info log
  String infoLog = glGetProgramInfoLog(program, glGetProgrami(program, GL_INFO_LOG_LENGTH));
  
  //if some log exists, append it 
  if (infoLog!=null &amp;&amp; infoLog.trim().length()!=0)
   log += infoLog;
  
  //if the link failed, throw some sort of exception
  if (glGetProgrami(program, GL_LINK_STATUS) == GL_FALSE)
   throw new LWJGLException(
     "Failure in linking program. Error log:\n" + infoLog);
  
  //detach and delete the shaders which are no longer needed
  glDetachShader(program, vertex);
  glDetachShader(program, fragment);
  glDeleteShader(vertex);
  glDeleteShader(fragment);
 }

 /** Compile the shader source as the given type and return the shader object ID. */
 protected int compileShader(String source, int type) throws LWJGLException {
  //create a shader object
  int shader = glCreateShader(type);
  //pass the source string
  glShaderSource(shader, source);
  //compile the source
  glCompileShader(shader);

  //if info/warnings are found, append it to our shader log
  String infoLog = glGetShaderInfoLog(shader,
    glGetShaderi(shader, GL_INFO_LOG_LENGTH));
  if (infoLog!=null &amp;&amp; infoLog.trim().length()!=0)
   log += getName(type) +": "+infoLog + "\n";
  
  //if the compiling was unsuccessful, throw an exception
  if (glGetShaderi(shader, GL_COMPILE_STATUS) == GL_FALSE)
   throw new LWJGLException("Failure in compiling " + getName(type)
     + ". Error log:\n" + infoLog);

  return shader;
 }

 protected String getName(int shaderType) {
  if (shaderType == GL_VERTEX_SHADER)
   return "GL_VERTEX_SHADER";
  if (shaderType == GL_FRAGMENT_SHADER)
   return "GL_FRAGMENT_SHADER";
  else
   return "shader";
 }

 /**
  * Make this shader the active program.
  */
 public void use() {
  glUseProgram(program);
 }

 /**
  * Destroy this shader program.
  */
 public void destroy() {
  glDeleteProgram(program);
 }

 /**
  * Gets the location of the specified uniform name.
  * @param str the name of the uniform
  * @return the location of the uniform in this program
  */
 public int getUniformLocation(String str) {
  return glGetUniformLocation(program, str);
 }
 
 /* ------ UNIFORM SETTERS/GETTERS ------ */
 
 /**
  * Sets the uniform data at the specified location (the uniform type may be int, bool or sampler2D). 
  * @param loc the location of the int/bool/sampler2D uniform 
  * @param i the value to set
  */
 public void setUniformi(int loc, int i) {
  if (loc==-1) return;
  glUniform1i(loc, i);
 }

 /**
  * Sends a 4x4 matrix to the shader program.
  * @param loc the location of the mat4 uniform
  * @param transposed whether the matrix should be transposed
  * @param mat the matrix to send
  */
 public void setUniformMatrix(int loc, boolean transposed, Matrix4f mat) {
  if (loc==-1) return;
  if (buf16Pool == null)
   buf16Pool = BufferUtils.createFloatBuffer(16);
  buf16Pool.clear();
  mat.store(buf16Pool);
  buf16Pool.flip();
  glUniformMatrix4(loc, transposed, buf16Pool);
 }
}


Fonte:&nbsp;https://github.com/mattdesl/lwjgl-basics/wiki/ShaderProgram-Utility