Graphics Programming
OpenGL Shading Language (GLSL)
Thorsten Thormählen
December 06, 2024
Part 9, Chapter 1
Thorsten Thormählen
December 06, 2024
Part 9, Chapter 1
This is the print version of the slides.
Advance slides with the → key or
by clicking on the right border of the slide
Slides can also be advanced by clicking on the left or right border of the slide.
| Type | Font | Examples |
|---|---|---|
| Variables (scalars) | italics | $a, b, x, y$ |
| Functions | upright | $\mathrm{f}, \mathrm{g}(x), \mathrm{max}(x)$ |
| Vectors | bold, elements row-wise | $\mathbf{a}, \mathbf{b}= \begin{pmatrix}x\\y\end{pmatrix} = (x, y)^\top,$ $\mathbf{B}=(x, y, z)^\top$ |
| Matrices | Typewriter | $\mathtt{A}, \mathtt{B}= \begin{bmatrix}a & b\\c & d\end{bmatrix}$ |
| Sets | calligraphic | $\mathcal{A}, B=\{a, b\}, b \in \mathcal{B}$ |
| Number systems, Coordinate spaces | double-struck | $\mathbb{N}, \mathbb{Z}, \mathbb{R}^2, \mathbb{R}^3$ |
progID = glCreateProgram();
vertID = glCreateShader(GL_VERTEX_SHADER); fragID = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(vertID, 1, &vertShaderSrcCodeString, &vStrLength); glShaderSource(fragID, 1, &fragShaderSrcCodeString, &fStrLength); glCompileShader(vertID); glCompileShader(fragID);
glAttachShader(progID, vertID); glAttachShader(progID, fragID); glLinkProgram(progID);
glUseProgram(progID);
glDeleteProgram(progID); glDeleteShader(vertID); glDeleteShader(fragID);
float, vec2, vec3, vec4, mat2, mat3, mat4int, ivec2, ivec3, ivec4, uint, uvec2, uvec3, uvec4bool, bvec2, bvec3, bvec4sampler2D, sampler3D, samplerCube, ...
struct Vertex {
float val1;
int val2;
bool val3;
};float a[16];
float a = float(1);
if, if()elsefor, while, do{}while()return, break, continueunsigned, byte, short, long types, no unionswitch()case// construction vec2 a = vec2(1.0, 2.0); vec3 b = vec3(1.0,-1.0, 1.0); vec4 c = vec4(1.0, 2.0, 3.0, 4.0); vec4 allOne = vec4(1.0); vec4 d = vec4(a, a); vec4 e = vec4(b, 1.0); // accessing elements float f = b[1]; // is -1.0 float g = b.y; // is -1.0 as well //conversion d = c.rgba; // stays a 4-vector b = c.xyz; // convert to 3-vector a = c.xy; // convert to 2-vector e = c.xxyy; // e = (1.0, 1.0, 2.0, 2.0) "swizzling" e.xz = vec2(0.5, 0.6); // e = (0.5, 1.0, 0.6, 2.0)
// construction
mat4 a = mat4(0.0, 0.1, 0.2, 0.3, // column major order:
0.4, 0.5, 0.6, 0.7, // transposed of the
0.8, 0.9, 1.0, 1.1, // usual interpretation
1.2, 1.3, 1.4, 1.5);
mat3 b = mat3(1.0); // identity matrix
// conversion
mat3 c = mat3(a); // upper 3x3 matrix
vec4 d = a[1]; // d = (0.4, 0.5, 0.6, 0.7)
// operations
vec4 e = a * vec4(1.0);
mat4 f = 2.0 * a - mat4(1.0);
class Renderer {
private:
struct Vertex
{
float position[3];
float color[4];
};
private:
enum {Triangle, numVAOs};
enum {TriangleAll, numVBOs};
GLuint vaoID[numVAOs];
GLuint bufID[numVBOs];
int triangleVertNo;
GLuint progID;
GLuint vertID;
GLuint fragID;
GLint vertexLoc;
GLint colorLoc;
public:
// constructor
Renderer() : triangleVertNo(0), progID(0), vertID(0),
fragID(0), vertexLoc(-1), colorLoc(-1) {}
//destructor
~Renderer() {
glDeleteVertexArrays(numVAOs, vaoID);
glDeleteBuffers(numVBOs, bufID);
glDeleteProgram(progID);
glDeleteShader(vertID);
glDeleteShader(fragID);
}
public:
void init() {
initExtensions();
glEnable(GL_DEPTH_TEST);
glEnable(GL_DEPTH);
setupShaders();
// create a Vertex Array Objects (VAO)
glGenVertexArrays(numVAOs, vaoID);
// generate a Vertex Buffer Object (VBO)
glGenBuffers(numVBOs, bufID);
// binding the Triangle VAO
glBindVertexArray(vaoID[Triangle]);
float triangleVertexData[] = {
0.0f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
-0.5f,-0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
0.5f,-0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f,
};
triangleVertNo = 3;
glBindBuffer(GL_ARRAY_BUFFER, bufID[TriangleAll]);
glBufferData(GL_ARRAY_BUFFER, triangleVertNo*sizeof(Vertex),
triangleVertexData, GL_STATIC_DRAW);
int stride = sizeof(Vertex);
char *offset = (char*)NULL;
// position
if(vertexLoc != -1) {
glVertexAttribPointer(vertexLoc, 3, GL_FLOAT,
GL_FALSE, stride, offset);
glEnableVertexAttribArray(vertexLoc);
}
// color
if(colorLoc != -1) {
offset = (char*)NULL + 3*sizeof(float);
glVertexAttribPointer(colorLoc, 4, GL_FLOAT,
GL_FALSE, stride, offset);
glEnableVertexAttribArray(colorLoc);
}
}
void setupShaders() {
// create shader
vertID = glCreateShader(GL_VERTEX_SHADER);
fragID = glCreateShader(GL_FRAGMENT_SHADER);
// load shader source from file
std::string vs = loadShaderSrc("./first.vert");
const char* vss = vs.c_str();
std::string fs = loadShaderSrc("./first.frag");
const char* fss = fs.c_str();
// specify shader source
glShaderSource(vertID, 1, &(vss), NULL);
glShaderSource(fragID, 1, &(fss), NULL);
// compile the shader
glCompileShader(vertID);
glCompileShader(fragID);
// check for errors
printShaderInfoLog(vertID);
printShaderInfoLog(fragID);
// create program and attach shaders
progID = glCreateProgram();
glAttachShader(progID, vertID);
glAttachShader(progID, fragID);
// "outColor" is a user-provided OUT variable
// of the fragment shader.
// Its output is bound to the first color buffer
// in the framebuffer
glBindFragDataLocation(progID, 0, "outputColor");
// link the program
glLinkProgram(progID);
// output error messages
printProgramInfoLog(progID);
// "inputPosition" and "inputColor" are user-provided
// IN variables of the vertex shader.
// Their locations are stored to be used later with
// glEnableVertexAttribArray()
vertexLoc = glGetAttribLocation(progID,"inputPosition");
colorLoc = glGetAttribLocation(progID, "inputColor");
}
void resize(int w, int h) {
glViewport(0, 0, w, h);
}
void display() {
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(progID);
// bind Triangle VAO
glBindVertexArray(vaoID[Triangle]);
// render data
glDrawArrays(GL_TRIANGLES, 0, triangleVertNo);
}
private:
void printShaderInfoLog(GLuint obj) {
int infoLogLength = 0;
int returnLength = 0;
char *infoLog;
glGetShaderiv(obj, GL_INFO_LOG_LENGTH,&infoLogLength);
if (infoLogLength > 0) {
infoLog = (char *)malloc(infoLogLength);
glGetShaderInfoLog(obj, infoLogLength,
&returnLength, infoLog);
printf("%s\n",infoLog);
free(infoLog);
}
}
void printProgramInfoLog(GLuint obj) {
int infoLogLength = 0;
int returnLength = 0;
char *infoLog;
glGetProgramiv(obj, GL_INFO_LOG_LENGTH,&infoLogLength);
if (infoLogLength > 0) {
infoLog = (char *)malloc(infoLogLength);
glGetProgramInfoLog(obj, infoLogLength,
&returnLength, infoLog);
printf("%s\n",infoLog);
free(infoLog);
}
}
std::string loadShaderSrc(const std::string& filename) {
std::ifstream is(filename);
if (is.is_open()) {
std::stringstream buffer;
buffer << is.rdbuf();
return buffer.str();
}
cerr << "Unable to open file " << filename << endl;
exit(1);
}
};
#version 140
in vec3 inputPosition;
in vec4 inputColor;
out vec3 forFragColor;
void main(){
forFragColor = inputColor.rgb;
gl_Position = vec4(inputPosition, 1.0);
}#version 140
in vec3 forFragColor;
out vec4 outputColor;
void main() {
outputColor = vec4(forFragColor,1.0);
}in variables
in variables, which are automatically generated, and user-defined
in variables,
which must be passed by the application
To use the data of VBOs for the used-defined
in
variables, the usual procedure will be as follows:
glGetAttribLocation a location identifier for an in variable is queried.
For example, when the variable in the shader code is called "inputColor" int colorLoc = glGetAttribLocation(progID, "inputColor");
glVertexAttribPointer(colorLoc, size, type, normalized, stride, offset) then defines the mapping between an in variable
and VBO attribute
glEnableVertexAttribArray(colorLoc);
glDrawArray or glDrawElements with activated VBO the in variable
of the vertex shader is then filled with the attribute data for each drawn vertex
out variables of the vertex shader are interpolated in the rasterizer and the interpolated values are supplied as in variables
to the fragment shader
out variables of the fragment shader will be sent to the framebuffer
out variable "outputColor" should be written into the first color buffer
of the framebuffer, this can be achieved by glBindFragDataLocation(progID, 0, "outputColor");
in variables, uniform variables are another way to pass data to a shaderin variables that contain the vertex attributes, the uniform variables
include data that remains constant for all vertices during a call to glDrawArray or glDrawElements
uniform variable can be queried by paraLoc = glGetUniformLocation(progID, "parameter");
uniform variable can be set with
glUniform1i(paraLoc, 123);
glUniform3fv(threeVectorLoc, 1, threeVector);
glUniformMatrix4fv(modelviewLoc, 1, transpose, modelview);
uniform variables.
The functionality of the GL_MODELVIEW and GL_PROJECTION matrices (which are known from the fixed-function pipeline) are simulated.
class Renderer {
private:
struct Vertex {
float position[3];
float color[4];
};
public:
float t;
private:
enum {Triangle, numVAOs};
enum {TriangleAll, numVBOs};
GLuint vaoID[numVAOs];
GLuint bufID[numVBOs];
int triangleVertNo;
GLuint progID;
GLuint vertID;
GLuint fragID;
GLuint vertexLoc;
GLuint colorLoc;
GLuint projectionLoc;
GLuint modelviewLoc;
float projection[16]; // projection matrix
float modelview[16]; // modelview matrix
public:
// constructor
Renderer() : t(0.0f), triangleVertNo(0), progID(0), vertID(0), fragID(0),
vertexLoc(-1), colorLoc(-1), projectionLoc(-1), modelviewLoc(-1)
{}
//destructor
~Renderer() {
glDeleteVertexArrays(numVAOs, vaoID);
glDeleteBuffers(numVBOs, bufID);
glDeleteProgram(progID);
glDeleteShader(vertID);
glDeleteShader(fragID);
}
public:
void init() {
initExtensions();
glEnable(GL_DEPTH_TEST);
glEnable(GL_DEPTH);
setupShaders();
// create a Vertex Array Objects (VAO)
glGenVertexArrays(numVAOs, vaoID);
// generate a Vertex Buffer Object (VBO)
glGenBuffers(numVBOs, bufID);
// binding the Triangle VAO
glBindVertexArray(vaoID[Triangle]);
float triangleVertexData[] = {
0.0f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
-0.5f,-0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
0.5f,-0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f,
};
triangleVertNo = 3;
glBindBuffer(GL_ARRAY_BUFFER, bufID[TriangleAll]);
glBufferData(GL_ARRAY_BUFFER, triangleVertNo*sizeof(Vertex),
triangleVertexData, GL_STATIC_DRAW);
int stride = sizeof(Vertex);
char *offset = (char*)NULL;
// position
if(vertexLoc != -1) {
glVertexAttribPointer(vertexLoc, 3, GL_FLOAT,
GL_FALSE, stride, offset);
glEnableVertexAttribArray(vertexLoc);
}
// color
if(colorLoc != -1) {
offset = (char*)NULL + 3*sizeof(float);
glVertexAttribPointer(colorLoc, 4, GL_FLOAT,
GL_FALSE, stride, offset);
glEnableVertexAttribArray(colorLoc);
}
}
void setupShaders() {
// create shader
vertID = glCreateShader(GL_VERTEX_SHADER);
fragID = glCreateShader(GL_FRAGMENT_SHADER);
// load shader source from file
std::string vs = loadShaderSrc("./uniform.vert");
const char* vss = vs.c_str();
std::string fs = loadShaderSrc("./uniform.frag");
const char* fss = fs.c_str();
// specify shader source
glShaderSource(vertID, 1, &(vss), NULL);
glShaderSource(fragID, 1, &(fss), NULL);
// compile the shader
glCompileShader(vertID);
glCompileShader(fragID);
// check for errors
printShaderInfoLog(vertID);
printShaderInfoLog(fragID);
// create program and attach shaders
progID = glCreateProgram();
glAttachShader(progID, vertID);
glAttachShader(progID, fragID);
// "outColor" is a user-provided OUT variable
// of the fragment shader.
// Its output is bound to the first color buffer
// in the framebuffer
glBindFragDataLocation(progID, 0, "outputColor");
// link the program
glLinkProgram(progID);
// output error messages
printProgramInfoLog(progID);
// "inputPosition" and "inputColor" are user-provided
// IN variables of the vertex shader.
// Their locations are stored to be used later with
// glEnableVertexAttribArray()
vertexLoc = glGetAttribLocation(progID,"inputPosition");
colorLoc = glGetAttribLocation(progID, "inputColor");
// "projection" and "modelview" are user-provided
// UNIFORM variables of the vertex shader.
// Their locations are stored to be used later
projectionLoc = glGetUniformLocation(progID, "projection");
modelviewLoc = glGetUniformLocation(progID, "modelview");
}
void resize(int w, int h) {
glViewport(0, 0, w, h);
// this function replaces gluPerspective
mat4Perspective(projection, 45.0f, (float)w/(float)h, 0.5f, 4.0f);
//mat4Print(projection);
}
void display() {
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// camera orbits in the y=2 plane
// and looks at the origin
// mat4LookAt replaces gluLookAt
double rad = M_PI / 180.0f * t;
mat4LookAt(modelview,
2.0f*cos(rad), 2.0f, 2.0f*sin(rad), // eye
0.0f, 0.0f, 0.0f, // look at
0.0f, 1.0f, 0.0f); // up
glUseProgram(progID);
// load the current projection and modelview matrix into the
// corresponding UNIFORM variables of the shader
glUniformMatrix4fv(projectionLoc, 1, false, projection);
glUniformMatrix4fv(modelviewLoc, 1, false, modelview);
// bind Triangle VAO
glBindVertexArray(vaoID[Triangle]);
// render data
glDrawArrays(GL_TRIANGLES, 0, triangleVertNo);
}
private:
void printShaderInfoLog(GLuint obj) {
int infoLogLength = 0;
int returnLength = 0;
char *infoLog;
glGetShaderiv(obj, GL_INFO_LOG_LENGTH,&infoLogLength);
if (infoLogLength > 0) {
infoLog = (char *)malloc(infoLogLength);
glGetShaderInfoLog(obj, infoLogLength, &returnLength, infoLog);
printf("%s\n",infoLog);
free(infoLog);
}
}
void printProgramInfoLog(GLuint obj) {
int infoLogLength = 0;
int returnLength = 0;
char *infoLog;
glGetProgramiv(obj, GL_INFO_LOG_LENGTH,&infoLogLength);
if (infoLogLength > 0) {
infoLog = (char *)malloc(infoLogLength);
glGetProgramInfoLog(obj, infoLogLength, &returnLength, infoLog);
printf("%s\n",infoLog);
free(infoLog);
}
}
std::string loadShaderSrc(const std::string& filename) {
std::ifstream is(filename);
if (is.is_open()) {
std::stringstream buffer;
buffer << is.rdbuf();
return buffer.str();
}
cerr << "Unable to open file " << filename << endl;
exit(1);
}
// the following functions are some matrix and vector helpers
// they work for this demo but in general it is recommended
// to use more advanced matrix libraries,
// e.g. OpenGL Mathematics (GLM)
float vec3Dot( float *a, float *b) {
return a[0]*b[0] + a[1]*b[1] + a[2]*b[2];
}
void vec3Cross( float *a, float *b, float *res) {
res[0] = a[1] * b[2] - b[1] * a[2];
res[1] = a[2] * b[0] - b[2] * a[0];
res[2] = a[0] * b[1] - b[0] * a[1];
}
void vec3Normalize(float *a) {
float mag = sqrt(a[0] * a[0] + a[1] * a[1] + a[2] * a[2]);
a[0] /= mag; a[1] /= mag; a[2] /= mag;
}
void mat4Identity( float *a) {
for (int i = 0; i < 16; ++i) a[i] = 0.0f;
for (int i = 0; i < 4; ++i) a[i + i * 4] = 1.0f;
}
void mat4Multiply(float *a, float *b, float *res) {
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
res[j*4 + i] = 0.0f;
for (int k = 0; k < 4; ++k) {
res[j*4 + i] += a[k*4 + i] * b[j*4 + k];
}
}
}
}
void mat4Perspective(float *a, float fov, float aspect, float zNear, float zFar) {
float f = 1.0f / float(tan (fov/2.0f * (M_PI / 180.0f)));
mat4Identity(a);
a[0] = f / aspect;
a[1 * 4 + 1] = f;
a[2 * 4 + 2] = (zFar + zNear) / (zNear - zFar);
a[3 * 4 + 2] = (2.0f * zFar * zNear) / (zNear - zFar);
a[2 * 4 + 3] = -1.0f;
a[3 * 4 + 3] = 0.0f;
}
void mat4LookAt(float *viewMatrix,
float eyeX, float eyeY, float eyeZ,
float centerX, float centerY, float centerZ,
float upX, float upY, float upZ) {
float dir[3], right[3], up[3], eye[3];
up[0]=upX; up[1]=upY; up[2]=upZ;
eye[0]=eyeX; eye[1]=eyeY; eye[2]=eyeZ;
dir[0]=centerX-eyeX; dir[1]=centerY-eyeY; dir[2]=centerZ-eyeZ;
vec3Normalize(dir);
vec3Cross(dir,up,right);
vec3Normalize(right);
vec3Cross(right,dir,up);
vec3Normalize(up);
// first row
viewMatrix[0] = right[0];
viewMatrix[4] = right[1];
viewMatrix[8] = right[2];
viewMatrix[12] = -vec3Dot(right, eye);
// second row
viewMatrix[1] = up[0];
viewMatrix[5] = up[1];
viewMatrix[9] = up[2];
viewMatrix[13] = -vec3Dot(up, eye);
// third row
viewMatrix[2] = -dir[0];
viewMatrix[6] = -dir[1];
viewMatrix[10] = -dir[2];
viewMatrix[14] = vec3Dot(dir, eye);
// forth row
viewMatrix[3] = 0.0f;
viewMatrix[7] = 0.0f;
viewMatrix[11] = 0.0f;
viewMatrix[15] = 1.0f;
}
void mat4Print(float* a) {
// opengl uses column major order
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
cout << a[j * 4 + i] << " ";
}
cout << endl;
}
}
};
#version 140
in vec3 inputPosition;
in vec4 inputColor;
uniform mat4 projection;
uniform mat4 modelview;
out vec3 forFragColor;
void main(){
forFragColor = inputColor.rgb;
gl_Position = projection * modelview * vec4(inputPosition, 1.0);
}#version 140
in vec3 forFragColor;
out vec4 outputColor;
void main() {
outputColor = vec4(forFragColor,1.0);
}
class Renderer {
private:
struct Vertex {
float position[3];
float texCoord[2];
float normal[3];
};
public:
float t;
int modeVal;
private:
enum {Scene, numVAOs};
enum {SceneAll, numVBOs};
GLuint vaoID[numVAOs];
GLuint bufID[numVBOs];
int sceneVertNo;
GLuint progID;
GLuint vertID;
GLuint fragID;
GLint vertexLoc;
GLint texCoordLoc;
GLint normalLoc;
GLint projectionLoc;
GLint modelviewLoc;
GLint normalMatrixLoc;
GLint modeLoc;
float projection[16]; // projection matrix
float modelview[16]; // modelview matrix
public:
// constructor
Renderer() : t(0.0), modeVal(1), sceneVertNo(0), progID(0),
vertID(0), fragID(0),
vertexLoc(-1), texCoordLoc(-1), normalLoc(-1),
projectionLoc(-1), modelviewLoc(-1),
normalMatrixLoc(-1), modeLoc(-1)
{}
//destructor
~Renderer() {
glDeleteVertexArrays(numVAOs, vaoID);
glDeleteBuffers(numVBOs, bufID);
glDeleteProgram(progID);
glDeleteShader(vertID);
glDeleteShader(fragID);
}
public:
void init() {
initExtensions();
glEnable(GL_DEPTH_TEST);
glEnable(GL_DEPTH);
setupShaders();
// create a Vertex Array Objects (VAO)
glGenVertexArrays(numVAOs, vaoID);
// generate a Vertex Buffer Object (VBO)
glGenBuffers(numVBOs, bufID);
// binding the pyramid VAO
glBindVertexArray(vaoID[Scene]);
std::vector <float> data;
int perVertexFloats = (3+2+3);
loadVertexData(string("teapot.vbo"), data, perVertexFloats);
sceneVertNo = int(data.size()) / perVertexFloats;
glBindBuffer(GL_ARRAY_BUFFER, bufID[SceneAll]);
glBufferData(GL_ARRAY_BUFFER, sceneVertNo*sizeof(Vertex),
&data[0], GL_STATIC_DRAW);
int stride = sizeof(Vertex);
char *offset = (char*)NULL;
// position
if(vertexLoc != -1) {
glVertexAttribPointer(vertexLoc, 3, GL_FLOAT, GL_FALSE,
stride, offset);
glEnableVertexAttribArray(vertexLoc);
}
// texCoord
if(texCoordLoc != -1) {
offset = (char*)NULL + 3*sizeof(float);
glVertexAttribPointer(texCoordLoc, 2, GL_FLOAT, GL_FALSE,
stride, offset);
glEnableVertexAttribArray(texCoordLoc);
}
// normal
if(normalLoc != -1) {
offset = (char*)NULL + (3+2)*sizeof(float);
glVertexAttribPointer(normalLoc, 3, GL_FLOAT, GL_FALSE,
stride, offset);
glEnableVertexAttribArray(normalLoc);
}
}
void setupShaders() {
// create shader
vertID = glCreateShader(GL_VERTEX_SHADER);
fragID = glCreateShader(GL_FRAGMENT_SHADER);
// load shader source from file
std::string vs = loadShaderSrc("./pass.vert");
const char* vss = vs.c_str();
std::string fs = loadShaderSrc("./pass.frag");
const char* fss = fs.c_str();
// specify shader source
glShaderSource(vertID, 1, &(vss), NULL);
glShaderSource(fragID, 1, &(fss), NULL);
// compile the shader
glCompileShader(vertID);
glCompileShader(fragID);
// check for errors
printShaderInfoLog(vertID);
printShaderInfoLog(fragID);
// create program and attach shaders
progID = glCreateProgram();
glAttachShader(progID, vertID);
glAttachShader(progID, fragID);
// "outColor" is a user-provided OUT variable
// of the fragment shader.
// Its output is bound to the first color buffer
// in the framebuffer
glBindFragDataLocation(progID, 0, "outputColor");
// link the program
glLinkProgram(progID);
// output error messages
printProgramInfoLog(progID);
// retrieve the location of the IN variables of the vertex shader.
vertexLoc = glGetAttribLocation(progID,"inputPosition");
texCoordLoc = glGetAttribLocation(progID,"inputTexCoord");
normalLoc = glGetAttribLocation(progID, "inputNormal");
// retrieve the location of the UNIFORM variables of the vertex shader.
projectionLoc = glGetUniformLocation(progID, "projection");
modelviewLoc = glGetUniformLocation(progID, "modelview");
normalMatrixLoc = glGetUniformLocation(progID, "normalMat");
modeLoc = glGetUniformLocation(progID, "mode");
}
void resize(int w, int h) {
glViewport(0, 0, w, h);
// this function replaces gluPerspective
mat4Perspective(projection, 30.0f, (float)w/(float)h, 0.5f, 4.0f);
// mat4Print(projection);
}
void display() {
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// camera orbits in the z=2 plane
// and looks at the origin
// mat4LookAt replaces gluLookAt
double rad = M_PI / 180.0f * t;
mat4LookAt(modelview,
1.5f*cos(rad), 1.5f*sin(rad), 1.5f, // eye
0.0f, 0.0f, 0.0f, // look at
0.0f, 0.0f, 1.0f); // up
float modelviewInv[16], normalmatrix[16];
mat4Invert(modelview, modelviewInv);
mat4Transpose(modelviewInv, normalmatrix);
glUseProgram(progID);
// load the current projection and modelview matrix into the
// corresponding UNIFORM variables of the shader
glUniformMatrix4fv(projectionLoc, 1, false, projection);
glUniformMatrix4fv(modelviewLoc, 1, false, modelview);
glUniformMatrix4fv(normalMatrixLoc, 1, false, normalmatrix);
glUniform1i(modeLoc, modeVal);
// bind Triangle VAO
glBindVertexArray(vaoID[Scene]);
// render data
glDrawArrays(GL_TRIANGLES, 0, sceneVertNo);
}
private:
void printShaderInfoLog(GLuint obj) {
int infoLogLength = 0;
int returnLength = 0;
char *infoLog;
glGetShaderiv(obj, GL_INFO_LOG_LENGTH,&infoLogLength);
if (infoLogLength > 0) {
infoLog = (char *)malloc(infoLogLength);
glGetShaderInfoLog(obj, infoLogLength, &returnLength, infoLog);
printf("%s\n",infoLog);
free(infoLog);
}
}
void printProgramInfoLog(GLuint obj) {
int infoLogLength = 0;
int returnLength = 0;
char *infoLog;
glGetProgramiv(obj, GL_INFO_LOG_LENGTH,&infoLogLength);
if (infoLogLength > 0) {
infoLog = (char *)malloc(infoLogLength);
glGetProgramInfoLog(obj, infoLogLength, &returnLength, infoLog);
printf("%s\n",infoLog);
free(infoLog);
}
}
std::string loadShaderSrc(const std::string& filename) {
std::ifstream is(filename);
if (is.is_open()) {
std::stringstream buffer;
buffer << is.rdbuf();
return buffer.str();
}
cerr << "Unable to open file " << filename << endl;
exit(1);
}
bool loadVertexData(std::string &filename, std::vector<float> &data,
unsigned perVertexFloats)
{
// read vertex data from file
ifstream input(filename.c_str());
if(!input) {
QMessageBox msgBox;
msgBox.setText("Can not find vertex data file");
msgBox.exec();
return false;
}
int numFloats;
double vertData;
if(input >> numFloats) {
if(numFloats > 0) {
data.resize(numFloats);
int i = 0;
while(input >> vertData && i < numFloats) {
// store it in the vector
data[i] = float(vertData);
i++;
}
if(i != numFloats || numFloats % perVertexFloats) return false;
}
}else{
return false;
}
return true;
}
// the following functions are some matrix and vector helpers,
// which work for this demo but in general it is recommended
// to use more advanced matrix libraries,
// e.g. OpenGL Mathematics (GLM)
float vec3Dot( float *a, float *b) {
return a[0]*b[0] + a[1]*b[1] + a[2]*b[2];
}
void vec3Cross( float *a, float *b, float *res) {
res[0] = a[1] * b[2] - b[1] * a[2];
res[1] = a[2] * b[0] - b[2] * a[0];
res[2] = a[0] * b[1] - b[0] * a[1];
}
void vec3Normalize(float *a) {
float mag = sqrt(a[0] * a[0] + a[1] * a[1] + a[2] * a[2]);
a[0] /= mag; a[1] /= mag; a[2] /= mag;
}
void mat4Identity( float *a) {
for (int i = 0; i < 16; ++i) a[i] = 0.0f;
for (int i = 0; i < 4; ++i) a[i + i * 4] = 1.0f;
}
void mat4Multiply(float *a, float *b, float *res) {
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
res[j*4 + i] = 0.0f;
for (int k = 0; k < 4; ++k) {
res[j*4 + i] += a[k*4 + i] * b[j*4 + k];
}
}
}
}
void mat4Perspective(float *a, float fov, float aspect,
float zNear, float zFar) {
float f = 1.0f / float(tan (fov/2.0f * (M_PI / 180.0f)));
mat4Identity(a);
a[0] = f / aspect;
a[1 * 4 + 1] = f;
a[2 * 4 + 2] = (zFar + zNear) / (zNear - zFar);
a[3 * 4 + 2] = (2.0f * zFar * zNear) / (zNear - zFar);
a[2 * 4 + 3] = -1.0f;
a[3 * 4 + 3] = 0.0f;
}
void mat4LookAt(float *viewMatrix,
float eyeX, float eyeY, float eyeZ,
float centerX, float centerY, float centerZ,
float upX, float upY, float upZ) {
float dir[3], right[3], up[3], eye[3];
up[0]=upX; up[1]=upY; up[2]=upZ;
eye[0]=eyeX; eye[1]=eyeY; eye[2]=eyeZ;
dir[0]=centerX-eyeX; dir[1]=centerY-eyeY; dir[2]=centerZ-eyeZ;
vec3Normalize(dir);
vec3Cross(dir,up,right);
vec3Normalize(right);
vec3Cross(right,dir,up);
vec3Normalize(up);
// first row
viewMatrix[0] = right[0];
viewMatrix[4] = right[1];
viewMatrix[8] = right[2];
viewMatrix[12] = -vec3Dot(right, eye);
// second row
viewMatrix[1] = up[0];
viewMatrix[5] = up[1];
viewMatrix[9] = up[2];
viewMatrix[13] = -vec3Dot(up, eye);
// third row
viewMatrix[2] = -dir[0];
viewMatrix[6] = -dir[1];
viewMatrix[10] = -dir[2];
viewMatrix[14] = vec3Dot(dir, eye);
// forth row
viewMatrix[3] = 0.0f;
viewMatrix[7] = 0.0f;
viewMatrix[11] = 0.0f;
viewMatrix[15] = 1.0f;
}
void mat4Print(float* a) {
// opengl uses column major order
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
cout << a[j * 4 + i] << " ";
}
cout << endl;
}
}
void mat4Transpose(float* a, float *transposed) {
int t = 0;
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
transposed[t++] = a[j * 4 + i];
}
}
}
bool mat4Invert(float* m, float *inverse) {
float inv[16];
inv[0] = m[5]*m[10]*m[15]-m[5]*m[11]*m[14]-m[9]*m[6]*m[15]+
m[9]*m[7]*m[14]+m[13]*m[6]*m[11]-m[13]*m[7]*m[10];
inv[4] = -m[4]*m[10]*m[15]+m[4]*m[11]*m[14]+m[8]*m[6]*m[15]-
m[8]*m[7]*m[14]-m[12]*m[6]*m[11]+m[12]*m[7]*m[10];
inv[8] = m[4]*m[9]*m[15]-m[4]*m[11]*m[13]-m[8]*m[5]*m[15]+
m[8]*m[7]*m[13]+m[12]*m[5]*m[11]-m[12]*m[7]*m[9];
inv[12]= -m[4]*m[9]*m[14]+m[4]*m[10]*m[13]+m[8]*m[5]*m[14]-
m[8]*m[6]*m[13]-m[12]*m[5]*m[10]+m[12]*m[6]*m[9];
inv[1] = -m[1]*m[10]*m[15]+m[1]*m[11]*m[14]+m[9]*m[2]*m[15]-
m[9]*m[3]*m[14]-m[13]*m[2]*m[11]+m[13]*m[3]*m[10];
inv[5] = m[0]*m[10]*m[15]-m[0]*m[11]*m[14]-m[8]*m[2]*m[15]+
m[8]*m[3]*m[14]+m[12]*m[2]*m[11]-m[12]*m[3]*m[10];
inv[9] = -m[0]*m[9]*m[15]+m[0]*m[11]*m[13]+m[8]*m[1]*m[15]-
m[8]*m[3]*m[13]-m[12]*m[1]*m[11]+m[12]*m[3]*m[9];
inv[13]= m[0]*m[9]*m[14]-m[0]*m[10]*m[13]-m[8]*m[1]*m[14]+
m[8]*m[2]*m[13]+m[12]*m[1]*m[10]-m[12]*m[2]*m[9];
inv[2] = m[1]*m[6]*m[15]-m[1]*m[7]*m[14]-m[5]*m[2]*m[15]+
m[5]*m[3]*m[14]+m[13]*m[2]*m[7]-m[13]*m[3]*m[6];
inv[6] = -m[0]*m[6]*m[15]+m[0]*m[7]*m[14]+m[4]*m[2]*m[15]-
m[4]*m[3]*m[14]-m[12]*m[2]*m[7]+m[12]*m[3]*m[6];
inv[10]= m[0]*m[5]*m[15]-m[0]*m[7]*m[13]-m[4]*m[1]*m[15]+
m[4]*m[3]*m[13]+m[12]*m[1]*m[7]-m[12]*m[3]*m[5];
inv[14]= -m[0]*m[5]*m[14]+m[0]*m[6]*m[13]+m[4]*m[1]*m[14]-
m[4]*m[2]*m[13]-m[12]*m[1]*m[6]+m[12]*m[2]*m[5];
inv[3] = -m[1]*m[6]*m[11]+m[1]*m[7]*m[10]+m[5]*m[2]*m[11]-
m[5]*m[3]*m[10]-m[9]*m[2]*m[7]+m[9]*m[3]*m[6];
inv[7] = m[0]*m[6]*m[11]-m[0]*m[7]*m[10]-m[4]*m[2]*m[11]+
m[4]*m[3]*m[10]+m[8]*m[2]*m[7]-m[8]*m[3]*m[6];
inv[11]= -m[0]*m[5]*m[11]+m[0]*m[7]*m[9]+m[4]*m[1]*m[11]-
m[4]*m[3]*m[9]-m[8]*m[1]*m[7]+m[8]*m[3]*m[5];
inv[15]= m[0]*m[5]*m[10]-m[0]*m[6]*m[9]-m[4]*m[1]*m[10]+
m[4]*m[2]*m[9]+m[8]*m[1]*m[6]-m[8]*m[2]*m[5];
float det = m[0]*inv[0]+m[1]*inv[4]+m[2]*inv[8]+m[3]*inv[12];
if (det == 0) return false;
det = 1.0f / det;
for (int i = 0; i < 16; i++) inverse[i] = inv[i] * det;
return true;
}
};
#version 140
in vec3 inputPosition;
in vec2 inputTexCoord;
in vec3 inputNormal;
uniform mat4 projection, modelview, normalMat;
uniform int mode;
out vec4 forFragColor;
void main(){
gl_Position = projection * modelview * vec4(inputPosition, 1.0);
vec4 normal = normalMat * vec4(inputNormal, 0.0);
if(mode == 1) forFragColor = normal;
if(mode == 2) forFragColor = vec4(inputNormal, 1.0);
if(mode == 3) forFragColor = gl_Position;
if(mode == 4) forFragColor = vec4(inputPosition, 1.0);
if(mode == 5) forFragColor = vec4(inputTexCoord, 0.0, 1.0);
}#version 140
in vec4 forFragColor;
out vec4 outputColor;
void main() {
outputColor = forFragColor;
}uniform variable of the type sampler must be defined: For example, in case of a 2D texture: uniform sampler2D myTexture;
texture(...) the color value at the texture coordinate $(s,t)$ is read: texture(myTexture, vec2(s,t))
glGenTexture and glBindTexture, parameters are set with
glTexParameter, and the texture data is passed with glTexImage (as discussed in Chapter 7)
sampler variable must be queried
texLoc = glGetUniformLocation(progID, "myTexture");
sampler variable: glActiveTexture(GL_TEXTURE0); // activate texture unit 0 glBindTexture(GL_TEXTURE_2D, texID); // bind texture glUniform1i(texLoc, 0); // inform the shader to use texture unit 0
class Renderer {
private:
struct Vertex {
float position[3];
float color[4];
float texCoord[2];
float normal[3];
};
public:
float t;
private:
enum {Pyramid, numVAOs};
enum {PyramidAll, numVBOs};
GLuint vaoID[numVAOs];
GLuint bufID[numVBOs];
int pyramidVertNo;
GLuint texID;
GLuint progID;
GLuint vertID;
GLuint fragID;
GLint vertexLoc;
GLint colorLoc;
GLint texCoordLoc;
GLint normalLoc;
GLint projectionLoc;
GLint modelviewLoc;
GLint texLoc;
float projection[16]; // projection matrix
float modelview[16]; // modelview matrix
public:
// constructor
Renderer() : t(0.0), pyramidVertNo(0), texID(0), progID(0), vertID(0), fragID(0),
vertexLoc(-1), colorLoc(-1), texCoordLoc(-1), normalLoc(-1),
projectionLoc(-1), modelviewLoc(-1), texLoc(-1)
{}
//destructor
~Renderer() {
glDeleteVertexArrays(numVAOs, vaoID);
glDeleteBuffers(numVBOs, bufID);
glDeleteProgram(progID);
glDeleteShader(vertID);
glDeleteShader(fragID);
}
public:
void init() {
initExtensions();
glEnable(GL_DEPTH_TEST);
glEnable(GL_DEPTH);
setupShaders();
// create a Vertex Array Objects (VAO)
glGenVertexArrays(numVAOs, vaoID);
// generate a Vertex Buffer Object (VBO)
glGenBuffers(numVBOs, bufID);
// bind the pyramid VAO
glBindVertexArray(vaoID[Pyramid]);
float pyramidVertexData[] = {
0.0f, 0.0f, 2.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.5f, 1.0f, 0.0000f,-0.9701f, 0.2425f,
-0.5f,-0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0000f,-0.9701f, 0.2425f,
0.5f,-0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0000f,-0.9701f, 0.2425f,
0.0f, 0.0f, 2.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.5f, 1.0f, 0.9701f, 0.0000f, 0.2425f,
0.5f,-0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.9701f, 0.0000f, 0.2425f,
0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.9701f, 0.0000f, 0.2425f,
0.0f, 0.0f, 2.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.5f, 1.0f, 0.0000f, 0.9701f, 0.2425f,
0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0000f, 0.9701f, 0.2425f,
-0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0000f, 0.9701f, 0.2425f,
0.0f, 0.0f, 2.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.5f, 1.0f,-0.9701f, 0.0000f, 0.2425f,
-0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f,-0.9701f, 0.0000f, 0.2425f,
-0.5f,-0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f,-0.9701f, 0.0000f, 0.2425f
};
pyramidVertNo = 12;
glBindBuffer(GL_ARRAY_BUFFER, bufID[PyramidAll]);
glBufferData(GL_ARRAY_BUFFER, pyramidVertNo*sizeof(Vertex),
pyramidVertexData, GL_STATIC_DRAW);
int stride = sizeof(Vertex);
char *offset = (char*)NULL;
// position
if(vertexLoc != -1) {
glVertexAttribPointer(vertexLoc, 3, GL_FLOAT, GL_FALSE, stride, offset);
glEnableVertexAttribArray(vertexLoc);
}
// color
if(colorLoc != -1) {
offset = (char*)NULL + 3*sizeof(float);
glVertexAttribPointer(colorLoc, 4, GL_FLOAT, GL_FALSE, stride, offset);
glEnableVertexAttribArray(colorLoc);
}
// texCoord
if(texCoordLoc != -1) {
offset = (char*)NULL + (3+4)*sizeof(float);
glVertexAttribPointer(texCoordLoc, 2, GL_FLOAT, GL_FALSE, stride, offset);
glEnableVertexAttribArray(texCoordLoc);
}
// normal
if(normalLoc != -1) {
offset = (char*)NULL + (3+4+2)*sizeof(float);
glVertexAttribPointer(normalLoc, 3, GL_FLOAT, GL_FALSE, stride, offset);
glEnableVertexAttribArray(normalLoc);
}
std::string fileName("./checkerboard.ppm");
texID = loadTexture(fileName);
}
void setupShaders() {
// create shader
vertID = glCreateShader(GL_VERTEX_SHADER);
fragID = glCreateShader(GL_FRAGMENT_SHADER);
// load shader source from file
std::string vs = loadShaderSrc("./texture.vert");
const char* vss = vs.c_str();
std::string fs = loadShaderSrc("./texture.frag");
const char* fss = fs.c_str();
// specify shader source
glShaderSource(vertID, 1, &(vss), NULL);
glShaderSource(fragID, 1, &(fss), NULL);
// compile the shader
glCompileShader(vertID);
glCompileShader(fragID);
// check for errors
printShaderInfoLog(vertID);
printShaderInfoLog(fragID);
// create program and attach shaders
progID = glCreateProgram();
glAttachShader(progID, vertID);
glAttachShader(progID, fragID);
// "outColor" is a user-provided OUT variable
// of the fragment shader.
// Its output is bound to the first color buffer
// in the framebuffer
glBindFragDataLocation(progID, 0, "outputColor");
// link the program
glLinkProgram(progID);
// output error messages
printProgramInfoLog(progID);
// retrieve the location of the IN variables of the vertex shader.
vertexLoc = glGetAttribLocation(progID,"inputPosition");
colorLoc = glGetAttribLocation(progID, "inputColor");
texCoordLoc = glGetAttribLocation(progID,"inputTexCoord");
normalLoc = glGetAttribLocation(progID, "inputNormal");
// retrieve the location of the UNIFORM variables of the vertex shader.
projectionLoc = glGetUniformLocation(progID, "projection");
modelviewLoc = glGetUniformLocation(progID, "modelview");
texLoc = glGetUniformLocation(progID, "myTexture");
}
void resize(int w, int h) {
glViewport(0, 0, w, h);
// this function replaces gluPerspective
mat4Perspective(projection, 30.0f, (float)w/(float)h, 1.0f, 10.0f);
// mat4Print(projection);
}
void display() {
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// camera orbits in the z=5 plane
// and looks at the origin
// mat4LookAt replaces gluLookAt
double rad = M_PI / 180.0f * t;
mat4LookAt(modelview,
5.0f*cos(rad), 5.0f*sin(rad), 5.0f, // eye
0.0f, 0.0f, 0.5f, // look at
0.0f, 0.0f, 1.0f); // up
glUseProgram(progID);
// load the current projection and modelview matrix into the
// corresponding UNIFORM variables of the shader
glUniformMatrix4fv(projectionLoc, 1, false, projection);
glUniformMatrix4fv(modelviewLoc, 1, false, modelview);
// activate texture unit 0
glActiveTexture(GL_TEXTURE0);
// bind texture
glBindTexture(GL_TEXTURE_2D, texID);
// inform the shader to use texture unit 0
glUniform1i(texLoc, 0);
// bind pyramid VAO
glBindVertexArray(vaoID[Pyramid]);
// render data
glDrawArrays(GL_TRIANGLES, 0, pyramidVertNo);
}
private:
void printShaderInfoLog(GLuint obj) {
int infoLogLength = 0;
int returnLength = 0;
char *infoLog;
glGetShaderiv(obj, GL_INFO_LOG_LENGTH,&infoLogLength);
if (infoLogLength > 0) {
infoLog = (char *)malloc(infoLogLength);
glGetShaderInfoLog(obj, infoLogLength, &returnLength, infoLog);
printf("%s\n",infoLog);
free(infoLog);
}
}
void printProgramInfoLog(GLuint obj) {
int infoLogLength = 0;
int returnLength = 0;
char *infoLog;
glGetProgramiv(obj, GL_INFO_LOG_LENGTH,&infoLogLength);
if (infoLogLength > 0) {
infoLog = (char *)malloc(infoLogLength);
glGetProgramInfoLog(obj, infoLogLength, &returnLength, infoLog);
printf("%s\n",infoLog);
free(infoLog);
}
}
std::string loadShaderSrc(const std::string& filename) {
std::ifstream is(filename);
if (is.is_open()) {
std::stringstream buffer;
buffer << is.rdbuf();
return buffer.str();
}
cerr << "Unable to open file " << filename << endl;
exit(1);
}
// the following functions are some matrix and vector helpers
// they work for this demo but in general it is recommended
// to use more advanced matrix libraries,
// e.g. OpenGL Mathematics (GLM)
float vec3Dot( float *a, float *b) {
return a[0]*b[0] + a[1]*b[1] + a[2]*b[2];
}
void vec3Cross( float *a, float *b, float *res) {
res[0] = a[1] * b[2] - b[1] * a[2];
res[1] = a[2] * b[0] - b[2] * a[0];
res[2] = a[0] * b[1] - b[0] * a[1];
}
void vec3Normalize(float *a) {
float mag = sqrt(a[0] * a[0] + a[1] * a[1] + a[2] * a[2]);
a[0] /= mag; a[1] /= mag; a[2] /= mag;
}
void mat4Identity( float *a) {
for (int i = 0; i < 16; ++i) a[i] = 0.0f;
for (int i = 0; i < 4; ++i) a[i + i * 4] = 1.0f;
}
void mat4Multiply(float *a, float *b, float *res) {
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
res[j*4 + i] = 0.0f;
for (int k = 0; k < 4; ++k) {
res[j*4 + i] += a[k*4 + i] * b[j*4 + k];
}
}
}
}
void mat4Perspective(float *a, float fov, float aspect,
float zNear, float zFar)
{
float f = 1.0f / float(tan (fov/2.0f * (M_PI / 180.0f)));
mat4Identity(a);
a[0] = f / aspect;
a[1 * 4 + 1] = f;
a[2 * 4 + 2] = (zFar + zNear) / (zNear - zFar);
a[3 * 4 + 2] = (2.0f * zFar * zNear) / (zNear - zFar);
a[2 * 4 + 3] = -1.0f;
a[3 * 4 + 3] = 0.0f;
}
void mat4LookAt(float *viewMatrix,
float eyeX, float eyeY, float eyeZ,
float centerX, float centerY, float centerZ,
float upX, float upY, float upZ) {
float dir[3], right[3], up[3], eye[3];
up[0]=upX; up[1]=upY; up[2]=upZ;
eye[0]=eyeX; eye[1]=eyeY; eye[2]=eyeZ;
dir[0]=centerX-eyeX; dir[1]=centerY-eyeY; dir[2]=centerZ-eyeZ;
vec3Normalize(dir);
vec3Cross(dir,up,right);
vec3Normalize(right);
vec3Cross(right,dir,up);
vec3Normalize(up);
// first row
viewMatrix[0] = right[0];
viewMatrix[4] = right[1];
viewMatrix[8] = right[2];
viewMatrix[12] = -vec3Dot(right, eye);
// second row
viewMatrix[1] = up[0];
viewMatrix[5] = up[1];
viewMatrix[9] = up[2];
viewMatrix[13] = -vec3Dot(up, eye);
// third row
viewMatrix[2] = -dir[0];
viewMatrix[6] = -dir[1];
viewMatrix[10] = -dir[2];
viewMatrix[14] = vec3Dot(dir, eye);
// forth row
viewMatrix[3] = 0.0;
viewMatrix[7] = 0.0;
viewMatrix[11] = 0.0;
viewMatrix[15] = 1.0f;
}
void mat4Print(float* a) {
// opengl uses column major order
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
cout << a[j * 4 + i] << " ";
}
cout << endl;
}
}
// returns a valid textureID on success, otherwise 0
GLuint loadTexture(std::string &filename) {
unsigned width;
unsigned height;
int level = 0;
int border = 0;
std::vector<unsigned char> imgData;
// load image data
if(!loadPPMImageFlipped(filename, width, height, imgData)) return 0;
// data is aligned in byte order
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
//request textureID
GLuint textureID;
glGenTextures( 1, &textureID);
// bind texture
glBindTexture( GL_TEXTURE_2D, textureID);
//define how to filter the texture (important but ignore for now)
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
//texture colors should replace the original color values
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); //GL_MODULATE
// specify the 2D texture map
glTexImage2D(GL_TEXTURE_2D, level, GL_RGB, width, height, border,
GL_RGB, GL_UNSIGNED_BYTE, &imgData[0]);
// return unique texture identifier
return textureID;
}
bool loadPPMImageFlipped(std::string &filename, unsigned &width,
unsigned &height, std::vector<unsigned char> &imgData)
{
ifstream input(filename.c_str(), ifstream::in | ifstream::binary);
if(!input) { // cast istream to bool to see if something went wrong
QMessageBox msgBox;
msgBox.setText(QString("Can not find texture data file ")
+ QString(filename.c_str()));
msgBox.exec();
return false;
}
input.unsetf(std::ios_base::skipws);
string line;
input >> line >> std::ws;
if (line != "P6") {
QMessageBox msgBox;
msgBox.setText("File is not PPM P6 raw format");
msgBox.exec();
return false;
}
width = 0;
height = 0;
unsigned depth = 0;
unsigned readItems = 0;
unsigned char lastCharBeforeBinary;
while (readItems < 3) {
input >> std::ws;
if(input.peek() != '#') {
if (readItems == 0) input >> width;
if (readItems == 1) input >> height;
if (readItems == 2) input >> depth >> lastCharBeforeBinary;
readItems++;
}else{ // skip comments
std::getline(input, line);
}
}
if(depth >= 256) {
QMessageBox msgBox;
msgBox.setText("Only 8-bit PPM format is supported");
msgBox.exec();
return false;
}
unsigned byteCount = width * height * 3;
imgData.resize(byteCount);
input.read((char*)&imgData[0], byteCount*sizeof(unsigned char));
// vertically flip the image because the image origin
// in OpenGL is the lower-left corner
unsigned char tmpData;
for(unsigned y=0; y < height / 2; y++) {
int sourceIndex = y * width * 3;
int targetIndex = (height-1-y) * width *3;
for(unsigned x=0; x < width*3; x++) {
tmpData = imgData[targetIndex];
imgData[targetIndex] = imgData[sourceIndex];
imgData[sourceIndex] = tmpData;
sourceIndex++;
targetIndex++;
}
}
return true;
}
};
#version 140
in vec3 inputPosition;
in vec4 inputColor;
in vec2 inputTexCoord;
in vec3 inputNormal;
uniform mat4 projection, modelview;
out vec3 forFragColor;
out vec2 forFragTexCoord;
void main(){
forFragColor = inputColor.rgb;
forFragTexCoord = inputTexCoord;
gl_Position = projection * modelview * vec4(inputPosition, 1.0);
}#version 140
in vec3 forFragColor;
in vec2 forFragTexCoord;
out vec4 outputColor;
uniform sampler2D myTexture;
void main() {
vec3 textureColor = vec3( texture(myTexture, forFragTexCoord) );
outputColor = vec4(forFragColor*textureColor,1.0);
}
#version 140
in vec3 forFragColor;
in vec2 forFragTexCoord;
out vec4 outputColor;
uniform sampler2D myTexture;
void main() {
vec3 textureColor = vec3( texture(myTexture, forFragTexCoord) );
outputColor = vec4(forFragColor*textureColor,1.0);
if(forFragTexCoord.x > 0.5) outputColor = vec4(1.0, 0.0, 0.0, 1.0);
}
#version 140
in vec3 forFragColor;
in vec2 forFragTexCoord;
out vec4 outputColor;
uniform sampler2D myTexture;
const vec2 texSize = vec2(256.0,256.0);
void main() {
vec3 tC = vec3( texture(myTexture, forFragTexCoord) );
vec3 tC2 = vec3( texture(myTexture, forFragTexCoord + vec2(1.0/texSize.x, 0.0) ) );
vec3 tC3 = vec3( texture(myTexture, forFragTexCoord + vec2(0.0, 1.0/texSize.y) ) );
if(abs(tC.x - tC2.x) > 0.01) {
outputColor = vec4(1.0,1.0,1.0,1.0);
}else {
if(abs(tC.x - tC3.x) > 0.01) {
outputColor = vec4(1.0,1.0,0.0,1.0);
}else {
outputColor = vec4(forFragColor*tC,1.0);
}
}
}
gl_FragDepth is changed by the fragment shader, the depth test cannot be performed early#version 420 layout(early_fragment_tests) in;
Please notify me by e-mail if you have questions, suggestions for improvement, or found typos: Contact