Shaders in OpenGL - University of Waterloo

Download Report

Transcript Shaders in OpenGL - University of Waterloo

Shaders in OpenGL
Marshall Hahn
Introduction to Shaders in OpenGL
vertex shaders, fragment shaders, and
how they communicate
 useful built-in functions and datatypes
 an example shader that implements bump
mapping
 how to compile, initialize and activate a
shader

OpenGL 1.5
Geometry
Vertices
Processed
Fragments
Per-Fragment
Operations
Pixels
Fragment
Processing
Per-Vertex
Operations
Frame
Buffer
Texture
Memory
Processed
Vertices
Primitive
Assembly
Primitive
Processing
Rasterization
Fragments
Primitives
Processed
Primitives
OpenGL 2.0
Geometry
Vertices
Processed
Fragments
Per-Fragment
Operations
Pixels
Fragment
Processing
Per-Vertex
Operations
Frame
Buffer
Texture
Memory
Processed
Vertices
Primitive
Assembly
Rasterization
Fragments
Primitives
Processed
Primitives
Primitive
Processing
Primitive
Processing
OpenGL Shading Language (GLSL)


A C-based language, has similar syntax and flow
control
a little more restrictive in some areas
 Functions:



return by value, pass by value
Has special built-in variables for input\output.
Their names always begin with gl_
Has built-in datatypes for matrices and vectors
Useful built-in functions: dot, cos, sin, mix, …
Swizzling
The normal structure-member selector (.) is also used to SWIZZLE
components of a vector: select or rearrange components by listing
their names after the swizzle operator (.)
 vec4 v4;
v4.rgba; // is a vec4 and the same as just using v4,
v4.rgb; // is a vec3, v4.b; // is a float,
v4.xy; // is a vec2,
v4.xgba; // is illegal - the component names do not come from // the
same set.
 The component names can be out of order to rearrange the
components, or they can be replicated to duplicate the components:

The Three Shader Variable Types



Uniform variables: can be changed once per primitive
 uniform bool bumpon;
Attribute variables: can be changed anytime, they
represent attributes that are associated with vertices
 attribute vec3 tangentVec;
Varying variables: are used communicate between
vertex shader and fragment shader. They are
automatically interpolated across the polygon.
 varying vec3 lightVec;
Normal Mapping
Normal Maps

An image where each pixel
represents a normal:
R



-> x, G -> y, B -> z
Each normal is perturbed a
small amount, so normal
maps tend to be “bluish” in
colour
R, G, and B each range from
0.0 to 1.0
N.x = ( R – 0.5 ) * 2.0, …
The Tangent Space
WCS
N V
Np
L
Point Source
T
Change of Basis from WCS to
Tangent Space
Suppose we have two vectors: S in
Tangent Space and O in World Space
 This is the transformation we need:

Normal Mapping Vertex Shader
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
uniform bool bumpon;
attribute vec3 tangentVec;
varying vec3 lightVec;
varying vec3 eyeVec;
void main (void)
{
vec4 ecPosition = gl_ModelViewMatrix * gl_Vertex;
gl_Position = ftransform();
gl_TexCoord[0] = gl_MultiTexCoord0;//texture mapping stuff
vec3 orgLightVec = ( gl_LightSource[0].position.xyz - ecPosition.xyz);
vec3 n = normalize(gl_NormalMatrix * gl_Normal);
vec3 t = normalize(gl_NormalMatrix * tangentVec);
vec3 b = cross(n, t);
lightVec.x = dot( orgLightVec, t);
lightVec.y = dot( orgLightVec, b);
lightVec.z = dot( orgLightVec, n);
vec3 position = -ecPosition.xyz;
eyeVec.x = dot( position, t);
eyeVec.y = dot( position, b);
eyeVec.z = dot( position, n);
}
Normal Mapping Fragment Shader
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
uniform bool bumpon;
uniform sampler2D normalMap;//must initialize with texture unit integer
varying vec3 lightVec;
varying vec3 eyeVec;
void main (void)
{
vec3 N = vec3(0.0, 0.0, 1.0);
if( bumpon ) N = normalize( ( (texture2D(normalMap, gl_TexCoord[0].xy).xyz) - 0.5) * 2.0 );
vec3 L = normalize(lightVec);
vec3 V = normalize(eyeVec);
vec3 R = reflect(L, N);
float pf = pow( dot(R, V), gl_FrontMaterial.shininess );
vec4 GlobalAmbient = gl_LightModel.ambient;
vec4 Ambient = gl_LightSource[0].ambient * gl_FrontMaterial.ambient;
vec4 Diffuse = gl_LightSource[0].diffuse * gl_FrontMaterial.diffuse * dot(N, L);
vec4 Specular = gl_LightSource[0].specular * gl_FrontMaterial.specular * pf;
vec4 color1 = GlobalAmbient + Ambient + Diffuse;
vec4 color2 = Specular;
gl_FragColor = clamp( color1 + color2, 0.0, 1.0 );
}
GLEE(GL Easy Extension library)




GLee (GL Easy Extension library) is a free
cross-platform extension loading library for
OpenGL
It provides seamless support for OpenGL
functions up to version 2.1 and over 360
extensions
http://elf-stone.com/glee.php
Microsoft’s OpenGL API only supports up to
OpenGL 1.1
Compilation
char* vertSrc = readShaderToString(vertShader);
char* fragSrc = readShaderToString(fragShader);
vs = glCreateShader(GL_VERTEX_SHADER);
fs = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(vs, 1, &vertSrc, NULL);
glShaderSource(fs, 1, &fragSrc, NULL);
glCompileShader(vs);
printOpenGLError(); // Check for OpenGL errors
glGetShaderiv(vs, GL_COMPILE_STATUS, &vertCompiled);
printShaderInfoLog(vs);
glCompileShader(fs);
printOpenGLError(); // Check for OpenGL errors
glGetShaderiv(fs, GL_COMPILE_STATUS, &fragCompiled);
printShaderInfoLog(fs);
if (!vertCompiled || !fragCompiled) exit(-1);
Compilation
// Create a program object and attach the two compiled shaders
int program = glCreateProgram();
glAttachShader(program, vs);
glAttachShader(program, fs);
// Link the program object and print out the info log
glLinkProgram(program);
printOpenGLError(); // Check for OpenGL errors
glGetProgramiv(program, GL_LINK_STATUS, &linked);
printProgramInfoLog();
if (!linked) exit(-1)
Initialization and Activation

Call glUseProgram( program ) to activate a shader.



The default functionality will be disabled
Can switch between multiple shaders while rendering a frame
glUseProgram(0) to turn on default pipeline
Initialization example:
GLint loc = glGetUniformLocation(program, "bumpon");
glUniform1i( loc, GL_TRUE );
GLint loc = glGetUniformLocation(program, "normalMap");
glUniform1i( loc, 0 );
GLint loc = glGetUniformLocation(program, "tangentVec");
glVertexAttrib3f(loc, v1, v2, v3);

Class shaderProgram
class shaderProgram {
public:
enum shaderT{
NORMAL,
NONE
};
static const unsigned NUM_OF_SHADERS = 2;
void initShaders() {
init(NORMAL, "shaders/normal.vert", "shaders/normal.frag");
}
inline void setActive(shaderT p);
inline void uniform1i(char *var, GLint val);
…
};
Usage
#include “shader.hpp”
void main(){
//called after OpenGL rendering context has been initialized
g_shader.initShaders();
…
g_shader.setActive(NORMAL);
g_shader. Uniform1i(“bumpon”, GL_TRUE);
…
}
For more information, see the spec

http://www.opengl.org/registry/doc/GLSLa
ngSpec.Full.1.20.8.pdf