Using Shaders
In "Modern" OpenGL |
Prof. David Bernstein |
Computer Science Department |
bernstdh@jmu.edu |
#ifndef FILE_UTILITIES__H #define FILE_UTILITIES_H #include <string> using namespace std; /** * /file * Functions for working with files. */ /** * Read a file into a stringstream. * * @param fileName The name of the file to read * @return A string containing the contents of the file */ string readFile(const char* fileName); #endif
#include <stdlib.h> #include <stdio.h> #include <iostream> #include <fstream> #include <sstream> #include "fileUtilities.h" string readFile(const char* fileName) { string contents; ifstream stream(fileName, ios::in); if(stream.is_open()){ stringstream sstr; sstr << stream.rdbuf(); contents = sstr.str(); stream.close(); } return contents; }
GLuint glCreateShader(GLenum shaderType)
void glShaderSource(GLuint shaderID,
GLsizei count,
const GLchar **source,
const GLint *length)
void glCompileShader(GLuint shaderID)
void glGetShaderiv(GLuint shaderID,
GLenum paramname,
GLint *params)
void glGetShaderInfoLog(GLuint shaderID,
GLsizei maxLength, GLsizei *actualLength,
GLchar *message)
GLuint buildShader(const char* fileName, GLenum shaderType) { // Create the handle/name/ID GLuint id = glCreateShader(shaderType); // Read the shader code from the file string code = readFile(fileName); if (code.size() == 0) return 0; // Compile the shader char const* codePointer = code.c_str(); glShaderSource(id, 1, &codePointer , NULL); glCompileShader(id); // Check the shader GLint ok = GL_FALSE; GLsizei messageLength = 0; glGetShaderiv(id, GL_COMPILE_STATUS, &ok); if (!ok) { glGetShaderiv(id, GL_INFO_LOG_LENGTH, &messageLength); GLchar errorMessage[messageLength + 1]; glGetShaderInfoLog(id, messageLength, NULL, &errorMessage[0]); printf("%s\n", &errorMessage[0]); } return id; }
GLuint glCreateProgram(void)
void glAttachShader(GLuint programID,
GLuint shaderID)
void glLinkProgram(GLuint programID)
void glGetProgramiv(GLuint programID,
GLenum paramname,
GLint *params)
void glGetProgramInfoLog(GLuint programID,
GLsizei maxLength, GLsizei *actualLength,
GLchar *message)
void glDetachShader(GLuint programID,
GLuint shaderID)
and
void glDeleteShader(GLuint id)
/** * Build a GLSL proram. * * @param vertexFileName The name of the file containg the vertex shader * @param fragmentFileName The name of the file containg the fragment shader */ GLuint buildProgram(const char* vertexFileName, const char* fragmentFileName);
GLuint buildProgram(const char* vertexFile, const char* fragmentFile){ // Read and compile the shaders GLuint vertexShaderID = buildShader(vertexFile, GL_VERTEX_SHADER); if (vertexShaderID == 0) return 0; GLuint fragmentShaderID = buildShader(fragmentFile, GL_FRAGMENT_SHADER); if (fragmentShaderID == 0) return 0; // Link the program GLuint programID = glCreateProgram(); glAttachShader(programID, vertexShaderID); glAttachShader(programID, fragmentShaderID); glLinkProgram(programID); // Check the program GLint ok = GL_FALSE; GLsizei messageLength = 0; glGetProgramiv(programID, GL_LINK_STATUS, &ok); if (!ok) { glGetProgramiv(programID, GL_INFO_LOG_LENGTH, &messageLength); GLchar errorMessage[messageLength + 1]; glGetProgramInfoLog(programID, messageLength, NULL, &errorMessage[0]); printf("%s\n", &errorMessage[0]); } // Cleanup glDetachShader(programID, vertexShaderID); glDetachShader(programID, fragmentShaderID); glDeleteShader(vertexShaderID); glDeleteShader(fragmentShaderID); return programID; }
// Initialize GLUT glutInit(&argc, argv); // Create the GLUT window width = 640; height = 480; window = createWindow("Using Shaders", width, height, 0, 0); // Initialize GLEW glewExperimental = GL_TRUE; if (glewInit() != GLEW_OK) { printf("Failed to initialize GLEW\n"); return -1; } // Register the callbacks glutCloseFunc(onClose); glutDisplayFunc(display);
// Process the command line arguments if (argc <= 1) { programID = buildProgram("lighting.vert", "lighting.frag"); } else { programID = buildProgram(argv[1], argv[2]); } if (programID == 0) { printf("Problem creating the shader program\n"); return -2; }
/** * Initilization tasks. */ void init() { // Create a vertex array object (VAO) glGenVertexArrays(1, &vertexArrayID); glBindVertexArray(vertexArrayID); // Set the clear color to JMU purple glClearColor(0.2706f, 0.0000f, 0.5176f, 0.000f); // Get a handle for the uniform named "MVP" for the given program ID mvpMatrixID = glGetUniformLocation(programID, "MVP"); // Define the projection matrix P = glm::ortho(-1.5f,1.5f,-1.5f,1.5f,0.0f,5.0f); // Define the camera matrix V = glm::lookAt( glm::vec3(0,-1,-2), // Camera is at (0,1,-2), in world space glm::vec3(0,0,0), // and looks at the origin glm::vec3(0,-1,0) // Head is down ); // Define the model matrix M = glm::mat4(1.0f); // The identity matrix MVP = P * V * M; // Remember: matrix multiplication is "backwards" // Get a handle for the uniform named "V" viewMatrixID = glGetUniformLocation(programID, "V"); // Get a handle for the uniform named "M" modelMatrixID = glGetUniformLocation(programID, "M"); // Get a handle for the uniform named "LightPosition_worldspace" lightID = glGetUniformLocation(programID, "lightPosition_worldspace"); // Define the position of the light lightPos = glm::vec3(4.0, 4.0, 4.0); // Enable depth testing glEnable(GL_DEPTH_TEST); // Accept fragment if it closer to the camera than the former one glDepthFunc(GL_LESS); // Cull each triangle whose normal is not towards the camera glEnable(GL_CULL_FACE); }
#include <algorithm> #include "trifileUtilities.h" Vertex* read(const char* fileName, int& size) { char s[80]; double x, y, z, nx, ny, nz; double minX, maxX, minY, maxY, minZ, maxZ; FILE* in; int br, bg, bb, fr, fg, fb, triangles; minX = minY = minZ = 10000000.0; maxX = maxY = maxZ = -10000000.0; in = fopen(fileName, "r"); // Read the number of triangles fscanf(in, "%d", &triangles); // The number of vertices (3 per triangle) size = triangles * 3; Vertex* vertices = new Vertex[size]; // Read the triangles for (int t=0; t<triangles; t++) { // The word "Triangle" fscanf(in, "%s",s); // Front face R,G,B and back face R,G,B fscanf(in, "%d %d %d %d %d %d",&fr,&fg,&fb,&br,&bg,&bb); // The three vertices for (int v=0; v<3; v++){ int index = t*3 + v; fscanf(in, "%lf %lf %lf %lf %lf %lf", &x, &y, &z, &nx, &ny, &nz); vertices[index].position[0] = x; vertices[index].position[1] = y; vertices[index].position[2] = z; vertices[index].normal[0] = nx; vertices[index].normal[1] = ny; vertices[index].normal[2] = nz; if (x < minX) minX = x; else if (x > maxX) maxX = x; if (y < minY) minY = y; else if (y > maxY) maxY = y; if (z < minZ) minZ = z; else if (z > maxZ) maxZ = z; vertices[index].color[0] = (GLfloat)fr / 255.; vertices[index].color[1] = (GLfloat)fg / 255.; vertices[index].color[2] = (GLfloat)fb / 255.; } } fclose(in); // Translate and scale double scale = std::min(2.0 / (maxX - minX), 2.0 / (maxY - minY)); double tx = -(maxX + minX)/2.0; double ty = -(maxY + minY)/2.0; for (int t=0; t<triangles; t++) { for (int v=0; v<3; v++){ int index = t*3 + v; vertices[index].position[0] = (vertices[index].position[0] + tx) * scale; vertices[index].position[1] = (vertices[index].position[1] + ty) * scale; vertices[index].position[2] = vertices[index].position[2] * scale; } } return &vertices[0]; }
/** * The display callback */ void display() { glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Use the appropriate shaders glUseProgram(programID); // Define uniforms for the currently bound shader glUniformMatrix4fv(mvpMatrixID, 1, GL_FALSE, &MVP[0][0]); glUniformMatrix4fv(modelMatrixID, 1, GL_FALSE, &M[0][0]); glUniformMatrix4fv(viewMatrixID, 1, GL_FALSE, &V[0][0]); glUniform3f(lightID, lightPos.x, lightPos.y, lightPos.z); // Describe the positions in the vertex array buffer glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID); glVertexAttribPointer( 0, // attribute identifier (used in the shader) 3, // size GL_FLOAT, // type GL_FALSE, // normalized or not? sizeof(Vertex), // stride reinterpret_cast<void*>(offsetof(Vertex, position)) // offset ); // Describe the colors in the vertex array buffer glEnableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID); glVertexAttribPointer( 1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void*>(offsetof(Vertex, color)) ); // Describe the normals in the vertex array buffer glEnableVertexAttribArray(2); glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID); glVertexAttribPointer( 2, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void*>(offsetof(Vertex, normal)) ); // Draw the triangles glDrawArrays(GL_TRIANGLES, 0, size); // Move the off-screen buffer to the screen glFlush(); }