/* display teapot with vertex and fragment shaders */ /* sets up elapsed time parameter for use by shaders */ #include #include #include const float nearVal = 1.0f; const float farVal = 300.0f; const float lightPos[3] = {3.0f, 3.0f, 3.0f}; int width = 512; int height = 512; GLint program = 0; GLint timeParam; /* shader reader */ /* creates null terminated string from file */ char* readShaderSource(const char* shaderFile) { struct stat statBuf; FILE* fp = fopen(shaderFile, "r"); char* buf; stat(shaderFile, &statBuf); buf = (char*) malloc(statBuf.st_size + 1 * sizeof(char)); fread(buf, 1, statBuf.st_size, fp); buf[statBuf.st_size] = '\0'; fclose(fp); return buf; \} /* error printing function */ static void checkError(GLint status, const char *msg) { if (!status) { printf("%s\n", msg); exit(EXIT_FAILURE); } } /* standard OpenGL initialization */ static void init() { const float teapotColor[] = {0.3f, 0.5f, 0.4f, 1.0f}; const float teapotSpecular[] = {0.8f, 0.8f, 0.8f, 1.0f}; const float teapotShininess[] = {80.0f}; glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, teapotColor); glMaterialfv(GL_FRONT, GL_SPECULAR, teapotSpecular); glMaterialfv(GL_FRONT, GL_SHININESS, teapotShininess); glClearColor(1.0f, 1.0f, 1.0f, 1.0f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslate(0.0f, 0.0f, 10.0f); glLightfv(GL_LIGHT0, GL_POSITION, lightPos); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_DEPTH_TEST); } /* GLSL initialization */ static void initShader(const GLchar* vShaderFile, const GLchar* fShaderFile) { GLint vShader = 0; GLint fShader = 0; GLint status = 0; /* read shader files */ GLchar* vSource = readShaderSource(vShaderFile); GLchar* fSource = readShaderSource(fShaderFile); /* create program and shader objects */ vShader = glCreateShaderObject(GL_VERTEX_SHADER); fShader = glCreateShaderObject(GL_FRAGMENT_SHADER); program = glCreateProgramObject(); /* attach shaders to the program object */ glAttachObject(program, vShader); glAttachObject(program, fShader); /* read shaders */ glShaderSource(vShader, 1, &vShaderFile, NULL); checkError(status, "Failed to read vertex shader"); glShaderSource(fShader, 1, &fShaderFile, NULL); checkError(status, "Failed to read vertex shader"); /* compile shaders */ glCompileShader(vShader); glCompileShader(fShader); /* error check */ glGetObjectParameteriv(vShader, GL_OBJECT_COMPILE_STATUS, &status); checkError(status, "Failed to compile the vertex shader."); glGetObjectParameteriv(fShader, GL_OBJECT_COMPILE_STATUS, &status); checkError(status, "Failed to compile the fragment shader."); /* link */ glLinkProgram(program); glGetObjectParameteriv(program, GL_OBJECT_LINK_STATUS, &status); checkError(status, "Failed to link the shader program object."); /* use program object */ glUseProgramObject(program); /* set up uniform parameter */ timeParam = glGetUniformLocation(program, "time"); } static void draw() { /* send elapsed time to shaders */ glUniform1f(timeParam, glutGet(GLUT_ELAPSED_TIME)); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glTranslatef(0.0f, 0.0f, -10.0f); glutSolidTeapot(2.0); glutSwapBuffers(); } static void reshape(int w, int h) \{ width = w; height = h; glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0, (double)width / (double)height, nearVal, farVal); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glViewport(0, 0, width, height); glutPostRedisplay(); } static void keyboard(unsigned char key, int x, int y) { switch (key) { case 27: case 'Q': case 'q': exit(EXIT_SUCCESS); break; default: break; } } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH); glutInitWindowSize(width, height); glutCreateWindow("Simple GLSL example"); glutDisplayFunc(draw); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); init(); initShader("vPhong.glsl","fPassThrough.glsl"); glutMainLoop(); } /* the following code is for the vertex and fragment shaders */ /* shader code is assumed to be in separate files */ // Vphong.glsl // modified Phong vertex shader uniform float time; void main() { gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; vec4 eyePosition = gl_ModelViewMatrix * gl_Vertex; vec4 eyeLightPos = gl_LightSource[0].position; vec3 eyeNormalVec = normalize(gl_NormalMatrix * gl_Normal); vec3 eyeLightVec = normalize(eyeLightPos.xyz - eyePosition.xyz); vec3 eyeViewVec = -normalize(eyePosition.xyz); vec3 eyeHalfVec = normalize(eyeLightVec + eyeViewVec); float Kd = max(dot(eyeLightVec, eyeNormalVec), 0.0); float Ks = pow(dot(eyeNormalVec, eyeHalfVec), gl_FrontMaterial.shininess); float Ka = 1.0; gl_FrontColor = Kd * gl_FrontLightProduct[0].diffuse + Ks * gl_FrontLightProduct[0].specular + gl_FrontLightModelProduct.sceneColor; } // fPassThrough.glsl // Pass through fragment shader. void main() { gl_FragColor = gl_Color; }