Graphics‎ > ‎Graphic API‎ > ‎OpenGl‎ > ‎

Shaders


Shaders are written in the OpenGL Shading Language (GLSL). This section is about compiling, linking and using them. In OpenGL a shader is a vertex shader or fragment shader. Then they are combined into a program and it is the program that is used to render with.


Shader object
Create
When you create a shader select the type of shader. The most common ones are GL_VERTEX_SHADER and GL_FRAGMENT_SHADER. After a program is linked it is possible to delete the shader object. Like a c executable you do not need to keep the source when you have the exe to run.

GLuint glCreateShader(GLenum type);
GLboolean glIsProgram(GLuint shader​);
void glDeleteShader(GLuint shader​);

Set source and compile
Provide the source to the shader with glShaderSource and it can be made up multiple sections. Then compile it with glCompileShader.

void glShaderSource(GLuint shader​, GLsizei count​, const GLchar **string​, const GLint *length​);
void glCompileShader(GLuint shader​);

Check the result of compilation
To check if the compile worked use glGetShaderiv to check for the GL_COMPILE_STATUS to be true. If not use glGetShaderInfoLog to get the log with the errors. GL_INFO_LOG_LENGTH can be used on glGetShaderiv to get the size of the log.

void glGetShaderiv(GLuint shader​, GLenum pname​, GLint *params​);
void glGetShaderInfoLog(GLuint shader​, GLsizei maxLength​, GLsizei *length​, GLchar *infoLog​);

Program object
Attatch the compiled shader objects to the program object and then link it.

Create

GLuint glCreateProgram(void);
GLboolean glIsProgram(GLuint program​);
void glDeleteProgram(GLuint program​);

Attatch Shaders

void glAttachShader(GLuint program​, GLuint shader​);
void glDetachShader(GLuint program​, GLuint shader​);

Link

void glLinkProgram(GLuint program​);

Check the result of Link
To verify the link use glGetProgramriv to check that GL_LINK_STATUS is GL_TRUE. Get the program info log with glGetProgramInfoLog if it fails.

void glGetProgramriv(GLuint program, GLenum pname​, GLint *params​);
void glGetProgramInfoLog(GLuint program​, GLsizei maxLength​, GLsizei *length​, GLchar *infoLog​);
void glValidateProgram(GLuint program​);


Use Shaders
A program is used by calling glUseProgram. Calling it with zero unbinds the program.

void glUseProgram(GLuint program​);

Set Shader Uniforms
Each uniform has a location in a form of a integer. To get the location use glGetUniformLocation. With the location it is possible to set the value with glUniform*. It takes the value to set it to and the location of the uniform. For textures assign the texture to a texture unit. Then assign the id of the texture unit to the uniform variable.

GLint glGetUniformLocation(GLuint program,  const GLchar *name);
void glUniform*(GLint location, ...);

Set Color numbers
The shader will output a number of color variables and glGetFragDataLocation is used to get the color number for a variable. That color number is then used in glDrawBuffers to select what color buffer the variable should write to.

GLint glGetFragDataLocation(GLuint program,const char * name);
void glDrawBuffers(GLsizei n,const GLenum *bufs);
void glNamedFramebufferDrawBuffers(GLuint framebuffer,GLsizei n,const GLenum *bufs);

Uniform blocks
Using a Interface Block in GLSL it is possible to fill in it with the content of a uniform buffer. In the program each Interface Block get's it's own block index. It is possible to query the program for it with glGetUniformBlockIndex or to set it with a layout in the shader. Then use the  glUniformBlockBinding to Interface Block to use a binding index. The binding index is part of the  OpenGL context and buffers are bound to the using glBindBufferBase with target GL_UNIFORM_BUFFER.

GLuint glGetUniformBlockIndex( GLuint program​​, const char *name​​ );
void glUniformBlockBinding(GLuint program​​, GLuint uniformBlockIndex​​, GLuint uniformBlockBinding​​);

When storing the data in the uniform buffer the correct memory layout needs to be used. There are four to select from, packed, shared, std140 and std430. Shared is the default one. If using packed or shared the driver pack things as it please and query functions must be used to get the correct positions to put things in the buffer. With std140 and std430 there are some rules on need to follow.

http://www.lighthouse3d.com/tutorials/glsl-tutorial/uniform-blocks/

Program pipeline object



Comments