Intro to Shaders & GLSL

advertisement
SHADERS/GLSL
CS 4363/6353
ANOTHER LOOK AT THE PIPELINE
Vertex Processing
Clipping/Assembly
Rasterization
Fragment
Processing
ANOTHER LOOK AT THE PIPELINE
Attributes (ins)
Vertex Processing
OpenGL Application
Clipping/Assembly
Client-side
Rasterization
Fragment
Processing
Server-side
ATTRIBUTES
•
Remember, these are values that are per vertex!
•
Denoted with keyword in
•
Are read-only
•
Maximum of 16 attributes per shader program
•
Always stored as a vec4, even if you declare it as a single float!
•
Examples:
• Raw vertex positions
• Normals
• Texture coordinates
•
Could also be other things?
ANOTHER LOOK AT THE PIPELINE
Attributes (ins)
Uniforms
OpenGL Application
Vertex Processing
Clipping/Assembly
Rasterization
Uniforms
Fragment
Processing
UNIFORMS
•
Uniforms are not individualized
•
Apply to all vertices/fragments
•
Denoted by the uniform keyword
•
Examples:
• Matrices (ModelView, Perspective)
• Light positions
ANOTHER LOOK AT THE PIPELINE
Attributes (ins)
Uniforms
Texture data
Vertex Processing
Clipping/Assembly
OpenGL Application
Rasterization
Texture data
Uniforms
Fragment
Processing
TEXTURE DATA
•
Remember, these are set up in hardware units
•
Textures can be in 1, 2 and 3 dimensions
•
Can also be in cube maps
•
Accessed in the fragment shader using sampler2D
ANOTHER LOOK AT THE PIPELINE
Attributes (ins)
Uniforms
Texture data
Vertex Processing
outs
OpenGL Application
New vertex positions
Clipping/Assembly
ins
Texture data
Uniforms
Fragment
Processing
GLSL
•
Must have a minimum of two shaders
•
Syntax is similar to C (it has a main)
•
Supports functions
•
Doesn’t support pointers!
•
Has variables similar to C
• bool finished = false;
• int myInt = -6;
• uint = 567u;
• float value = 42.0;
VECTORS
•
GLSL supports vectors with 2, 3 and 4elements
• vec2, vec3, vec4
• ivec2, ivec3, ivec4
• uvec2, uvec3, uvec4
• bvec2, bvec3, bvec4
•
Initialize with a “constructor”
• vec4 color = vec4 (1.0f, 0.0f, 1.0f, 1.0f);
•
Common operations
• result = myVec + yourVec;
• myVec += vec4 (1.0f, 0.5f, 0.4f, 0.2f);
• myVec *= 3.0f;
INDIVIDUAL ELEMENTS
•
Can access individual elements using
• xyzw – typically for positions
• rgba – usually for colors
• stpq – usually for texture coordinates
• … it’s your choice, but you can’t mix them!
•
Examples
• myVec.x = 4.0f;
• myVec.xy = vec2 (1.0f, 5.0f);
• myVec.xyz = yourVec.xyz;
• vColor.bgra = vOldColor.rgba; // called “swizzling”
A NOTE ABOUT EFFICIENCY & GOTCHAS
•
Vector operations are supported by hardware
•
Performed all at once!
•
Inefficient:
• vPos.x = vPos2.x + 1.0f;
• vPos.y = vPos2.y +3.0f;
• vPos.z = vPos2.z + 2.0f;
•
Efficient:
• vPos.xyz = vPos2.xyz + vec3 (1.0f, 3.0f, 2.0f);
•
Gotcha:
• If you don’t use an attribute or uniform, OpenGL “optimizes” by removing it!
MATRICES!
•
Several types in columns and rows:
• mat2x2 (or simply mat2)
• mat3x3 (or mat3)
• mat4x4 (or mat4)
• mat2x3 and mat2x4
• mat3x2 and mat3x4
• mat4x2 and mat4x3
MATRICES
•
Organized as an array of column vectors
• mMV[3] = vec4(1.0f, 0.0f, 1.0f, 1.0f);
• vec3 myVec = mMV[3].xyz;
•
Matrices can be multiplied by other matrices and vectors
•
Matrices have one nasty “constructor” and one good one
mat4 theMatrix = mat4 (1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
mat4 theMatrix = mat4(1.0f);
STORAGE QUALIFIERS
•
in – passed in from a previous stage
•
out – going to the next stage
•
const – a read-only variable (one that doesn’t change)
•
uniform – does not change across vertices
•
inout – only used in functions (it’s essentially a pointer)
•
in centroid/out centroid – used in multisampled buffers (interpolation)
•
noperspective – don’t use perspectively-correct interpolation
•
flat – don’t interpolate (colors) at all; declared in both vertex and frag shaders
•
smooth – the default interpolation
EXAMPLE
Perspectively interpolated
noperspective
http://wwwx.cs.unc.edu/~sud/courses/236/a6/
A SIDE-BY-SIDE COMPARISON
•
Show the relationship between client code and shader code
•
Assume you loaded a sphere, plane, or monkey face…
• numVertices – the number of vertices (duh!)
• vVerts – the position information of each vertex
• vNorms – the normal information of each vertex
glBindVertexArray(vao);
GLuint buffer;
buffer
glGenBuffers(1, &buffer);
Note: buffer “lives” on the graphics card in a nice, two-bedroom loft…
glBindVertexArray(vao);
GLuint buffer;
Hey – I’m active now
buffer
glGenBuffers(1, &buffer);
glBindBuffer (GL_ARRAY_BUFFER, buffer);
glBindVertexArray(vao);
GLuint buffer;
Now I know how big I am!
buffer
glGenBuffers(1, &buffer);
glBindBuffer (GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER,
numVertices*6*sizeof(GLfloat),
NULL, GL_STATIC_DRAW);
Why 6?
glBindVertexArray(vao);
GLuint buffer;
Now I’m putting vVerts at the beginning
buffer
glGenBuffers(1, &buffer);
vVerts
glBindBuffer (GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER,
numVertices*6*sizeof(GLfloat),
NULL, GL_STATIC_DRAW);
glBufferSubData (GL_ARRAY_BUFFER, 0,
numVertices*3*sizeof(GLfloat), vVerts);
glBufferSubData (GL_ARRAY_BUFFER,
numVertices*3*sizeof(GLfloat),
numVertices*3*sizeof(GLfloat), vNorms);
Put vVerts at 0… it’s pretty big
though…
I’m putting vNormals next
glBindVertexArray(vao);
GLuint buffer;
buffer
glGenBuffers(1, &buffer);
vVerts
vNorms
glBindBuffer (GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER,
numVertices*6*sizeof(GLfloat),
NULL, GL_STATIC_DRAW);
glBufferSubData (GL_ARRAY_BUFFER, 0,
numVertices*3*sizeof(GLfloat), vVerts);
glBufferSubData (GL_ARRAY_BUFFER,
numVertices*3*sizeof(GLfloat),
numVertices*3*sizeof(GLfloat), vNorms);
Put vNormals starting
right after that!
It’s pretty big
too…
WHAT WE HAVE SO FAR…
•
We have a buffer with an ID
•
That buffer lives on the graphics card
•
That buffer is full of vertex position/normal data
•
How do we get that info to our shader?
•
Immediately after this code, we put the following…
GLuint loc = glGetAttribLocation(shaderProgramID, "vPosition");
#version 150
in vec4 vPosition;
in vec3 vNormal;
out vec4 color;
// This will be referenced in your OpenGL program!!
// The normal of the vertex
// Out to fragment shader
uniform mat4 p;
uniform mat4 mv;
uniform vec4 light_pos;
// This is perpsective matrix
// This is the model-view matrix
// This is the light position
void main () {
gl_Position = p*mv*vPosition;
vec3 L = normalize (light_pos.xyz);
vec3 N = normalize (vNormal);
color = vColor*max(0.2f, dot(N, L));
}
GLuint loc = glGetAttribLocation(shaderProgramID, "vPosition");
glEnableVertexAttribArray(loc);
glVertexAttribPointer(loc, 3, GL_FLOAT, GL_FALSE, 0, 0);
Guys! I’m still active, remember?
buffer
vVerts
vNorms
#version 150
in vec4 vPosition;
in vec3 vNormal;
out vec4 color;
// This will be referenced in your OpenGL program!!
// The normal of the vertex
// Out to fragment shader
uniform mat4 p;
uniform mat4 mv;
uniform vec4 light_pos;
// This is perpsective matrix
// This is the model-view matrix
// This is the light position
void main () {
gl_Position = p*mv*vPosition;
vec3 L = normalize (light_pos.xyz);
vec3 N = normalize (vNormal);
color = vColor*max(0.2f, dot(N, L));
}
Tell vNormal where to look in me…
buffer
vVerts
vNorms
GLuint loc2 = glGetAttribLocation(shaderProgramID, "vNormal");
glEnableVertexAttribArray(loc2);
glVertexAttribPointer(loc2, 3, GL_FLOAT, GL_FALSE, 0,
BUFFER_OFFSET(numVertices*3*sizeof(GLfloat)));
#version 150
in vec4 vPosition;
in vec3 vNormal;
out vec4 color;
// This will be referenced in your OpenGL program!!
// The normal of the vertex
// Out to fragment shader
uniform mat4 p;
uniform mat4 mv;
uniform vec4 light_pos;
// This is perpsective matrix
// This is the model-view matrix
// This is the light position
void main () {
gl_Position = p*mv*vPosition;
vec3 L = normalize (light_pos.xyz);
vec3 N = normalize (vNormal);
color = vColor*max(0.2f, dot(N, L));
}
GLuint loc = glGetAttribLocation(shaderProgramID, "vPosition");
glEnableVertexAttribArray(loc);
glVertexAttribPointer(loc, 3, GL_FLOAT, GL_FALSE, 0, 0);
GLuint loc2 = glGetAttribLocation(shaderProgramID, "vNormal");
glEnableVertexAttribArray(loc2);
glVertexAttribPointer(loc2, 3, GL_FLOAT, GL_FALSE, 0,
BUFFER_OFFSET(numVertices*3*sizeof(GLfloat)));
#version 150
in vec4 vPosition;
in vec3 vNormal;
out vec4 color;
// This will be referenced in your OpenGL program!!
// The normal of the vertex
// Out to fragment shader
uniform mat4 p;
uniform mat4 mv;
uniform vec4 light_pos;
// This is perpsective matrix
// This is the model-view matrix
// This is the light position
void main () {
gl_Position = p*mv*vPosition;
vec3 L = normalize (light_pos.xyz);
vec3 N = normalize (vNormal);
color = vColor*max(0.2f, dot(N, L));
}
THE FRAGMENT SHADER
•
For every vertex shader out, there’s a fragment shader in
•
Value is smoothly interpolated from vertex shader
•
Fragment shaders have an out as well
• Called “output zero”
• Sent to color buffer
• Represents the color of the fragment
COMPILING AND LINKING SHADERS
GLint fShaderID = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource (fShaderID, 1, (const GLchar**)&shaderSource1, NULL);
glCompileShader(fShaderID);
GLint vShaderID = glCreateShader(GL_VERTEX_SHADER);
glShaderSource (vShaderID, 1, (const GLchar**)&shaderSource2, NULL);
glCompileShader(vShaderID);
GLuint programID = glCreateProgram(); // KEEP THIS!
glAttachShader(programID, vertexShaderID);
glAttachShader(programID, fragmentShaderID);
glLinkProgram (programID);
USING/DELETING
•
To use the shader:
• glUseProgram (GLuint progID);
• Any subsequent draw calls will use that shader
•
There are only a limited number of shaders on the graphics card (16)
•
When you’re done with one:
• glDeleteShader( GLuint progID);
#version 150
in vec4 vPosition;
in vec3 vNormal;
out vec4 color;
// This will be referenced in your OpenGL program!!
// The normal of the vertex
// Out to fragment shader
uniform mat4 p;
uniform mat4 mv;
uniform vec4 light_pos;
// This is perpsective matrix
// This is the model-view matrix
// This is the light position
void main () {
gl_Position = p*mv*vPosition;
vec3 L = normalize (light_pos.xyz);
vec3 N = normalize (vNormal);
color = vColor*max(0.2f, dot(N, L));
}
#version 150
out vec4 fColor;
in vec4 color;
void main () {
fColor = color;
}
// from the vertex shader
A NOTE ABOUT VERSIONS
•
Version number – minimum version supported
•
Version numbers changed!
• OpengGL 3.0 – GLSL version 1.3 (#version 130)
• OpenGL 3.1 – GLSL version 1.4 (#version 140)
• OpenGL 3.2 – GLSL version 1.5 (#version 150)
• OpenGL 3.3 – GLSL version 3.0 (#version 300)
• OpenGL 4.0 – GLSL version 4.0 (#version 400)
UNIFORMS
•
Persistent across all vertices
•
Can’t be marked as in/out
•
Can’t be interpolated
•
Always read-only
•
Find uniform variables using:
•
glGetUniformLocation (GLuint progID, const GLchar* varName);
SETTING UNIFORMS
•
•
Scalars and vectors (glUniformXY – where Y is the data type):
•
glUniform1f (GLuint location, GLfloat v0);
•
glUniform2f (GLuint location, GLfloat v0, GLfloat v1);
•
glUniform3f (GLuint location, GLfloat v0, GLfloat v1,
GLfloat v2);
•
glUniform4f (GLuint location, GLfloat v0, GLfloat v1,
GLfloat v2, GLfloat v3);
Example:
GLunit lightID = glGetUniformLocation (progID, “light_pos”);
glUniform4f (lightID, light_x, light_y, light_z, 1.0f);
SETTING UNIFORMS
•
•
Arrays are similar:
•
glUniform1fv (GLuint location, GLuint count, GLfloat* v);
•
glUniform2fv (GLuint location, GLuint count, GLfloat* v);
•
glUniform3fv (GLuint location, GLuint count, GLfloat* v);
•
glUniform4fv (GLuint location, GLuint count, GLfloat* v);
What’s the difference? Format of glUniformXYv
• X is how many elements are in each array
• count is how many of those arrays you have
• Y is the type
•
Example:
GLunit lightID = glGetUniformLocation (progID, “light_pos”);
GLfloat* myLightPosition[4] = {10.0f, 10.0f, 10.0f, 1.0f);
glUniform4fv (lightID, 1, myLightPosition);
SETTING UNIFORMS
•
Set uniform matrices by their dimension:
•
glUniformMatrix2fv (GLunit loc, GLuint count,
GLboolean transpose, GLfloat* m);
•
glUniformMatrix3fv (GLunit loc, GLuint count,
GLboolean transpose, GLfloat* m);
•
glUniformMatrix4fv (GLunit loc, GLuint count,
GLboolean transpose, GLfloat* m);
•
count represents the number of matrices (almost always 1)
•
transpose is used to indicate if the matrix is stored in column order
BUILT-IN GLSL FUNCTIONS
•
Tons of different mathematical functions
• Scalars
• Vectors
• Matrices
•
Robust trig functions:
• float x = sin (1.0);
// Also have cos, tan, atan, asin…
• vec4 y = sin (vec4(1.0f, 0.5f, 0.25f, 0.0f));
// Overloaded function
• float z = radians (45.0f);
// Convert from degrees to radians
• float z = degrees (0.6f);
// Convert from radians to degrees
BUILT-IN GLSL FUNCTIONS
•
Robust exponentials:
• vec2 results = pow (vec2(2, 3), vec2 (2, 2));
• log( ) – natural log
• exp( ) - ex
• log2( ) – log base 2
• exp2( ) – 2 to the power of…
• sqrt( )
// 2^2, 3^2
BUILT-IN GLSL FUNCTIONS
•
Geometric functions (generic “vec”)
• float length (vec x);
• float distance (vec p0, vec p1);
• float dot (vec x, vec y);
• vec3 cross (vec x, vec y);
• vec normalize (vec x);
• vec reflect (vec I, vec N); // I is incident vector (light/view) and N is normal
• vec refract(vec I, vec N, float eta);
• vec faceForward (vec N, vec I, vec nRef);// if dot(Nref, I) < 0, return N, else return -N
BUILT-IN GLSL FUNCTIONS
•
Matrices
• transpose( )
• determinant( )
• inverse( )
• outerProduct( )
•
Relational functions
• vec lessThan (vec x, vec y); && vec lessThanEqual (vec x, vec y);
• vec greaterThan (vec x, vec y);
• vec equal (vec x, vec y); && vec notEqual (vec x, vec y);
• bool any (bvec x);
// returns true if any booleans in x are true
• bool all (bvec x);
// returns true if all booleans in x are true
BUILT-IN GLSL FUNCTIONS
•
Common functions
•
abs, sign, floor, ceil, mod, min, max... yeah, yeah…
•
trunc(x) – nearest whole number not larger than the absolute value of x
•
round(x) – based on 0.5
•
roundEven(x) – “returns a value equal to the nearest integer to x.The fractional part of 0.5
will round toward the nearest even integer. For example, both 3.5 and 4.5 will round to
4.0.”
•
fract (x) – returns the fractional part
•
clamp(x, y, z) – returns x if it’s between y and z, else returns y or z
•
mix (x, y, a) – returns the linear blend of x and y, as a varies from 0 to 1
•
step (edge, x) – returns 0.0 if x < edge, 1.0f otherwise
•
smoothstep (edge0, edge1, x) – 0 if x < edge0, 1 if x > edge1, interpolated otherwise
LAST OF THE BUILT-INS
•
isnan(x) – true is x is not a number (NAN)
•
isinf(x) – returns true is x is +∞ or -∞
•
floatBitsToInt(x) – converts floating point values to ints
•
intBitstoFloat(x) – converts integers to floating points
Download