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, mat4
int, ivec2, ivec3, ivec4, uint, uvec2, uvec3, uvec4
bool, bvec2, bvec3, bvec4
sampler2D, sampler3D, samplerCube, ...
struct Vertex { float val1; int val2; bool val3; };
float a[16];
float a = float(1);
if, if()else
for, while, do{}while()
return, break, continue
unsigned, byte, short, long
types, no union
switch()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