Project 2

For this project, our goal was to learn about vertex and fragment shaders and how to apply them to models in OpenGL. The language of vertex and fragment shaders (GLSL) is similar to C which makes it easy for developing new shaders. Shaders are compiled before sending to the GPU for processing. To apply a shader to a particular model, first the model must be loaded from disk into the OpenGL context. Then the shader must be loaded from disk into a C style '0' terminated string and compiled and sent to the GPU.

Shaders can be anything from adding a cool effect to a model such as a brick pattern to an animated surface appearing like water. They can be procedural and they can be

In project 1, I loaded single models from the command line argument using argv. In this project however, I decided to incorporate a fully fledged GUI using Qt with a QGLWidget for rendering the OpenGL framebuffer. I chose Qt as my GUI framework because it plays nicely across platforms (Mac, Linux, and Windows). I'm a fanatic when it comes to seeing my code run on as many operating systems/devices as possible. Lately I've been embracing the cross-platform world and Qt makes it very nice to follow the compile once and run everywhere philosophy.

I created a main for manipulating the OpenGL scene and I used native system dialogs for opening files from disk and saving files to disk.

Application Windows

Main Window

Displays the GLWidget for rendering the OpenGL framebuffer and interacting with the OpenGL scene. The framebuffer can be saved to disk using a number of formats supported by Qt (PNG, JPG, BMP, etc.). Qt has a nice function for saving the contents of a QGLWidget to disk.

Menus

File menu - open Wavefront models, Save images of the framebuffer

Shaders menu - demo specific built in shaders, load custom shaders form disk, dynamically compile new shaders using a built in text editor, reset shaders (unload the program)

Brick Shader Options

Allows user to set options on the brick shader such as mortar color, brick color, brick size, and brick fraction. Resets the uniform values and updates the scene in real time.

Shader Editor

Built-in shader editor for on the fly compilation of vertex and fragment shaders. The shader compiler and linker will send an error message in the form of  a message box when it finds an error. This is helpful to the user to debug the programs. Possibly in a later version of this software, I could write a syntax highlighter as well as line indicators of where the errors occur during compile.

Initial shortcomings and how I overcame them

Initially, I wasn't able to get all shaders working correctly. The brick shader just showed up as black and the wave shader didn't animate. I couldn't figure out how to work with updating the uniform time value with each redraw. The shaders for setting the diffuse and specular diffuse colors worked, but that was about it.

Now, I have successfully implemented the wave shader and brick shader using uniform values. I struggled a while with the method for loading and compiling the shaders, but ultimately decided to use Qt's built in classes for working with shaders. This made processing shaders and setting uniform values extremely easy.

Qt and OpenGL Learning Curve

While developing this project, I had to figure out how to interact with OpenGL with Qt. Previously, I had just used GLUT as the window wrapper. GLUT is a good framework, but it's limited when it comes to developing fully fledged GUI based applications. Qt on the other hand is developed from the ground up to provide a native GUI for the user on a multitude of platforms.

One of the things I had to learn was how does glut's functions for the main event loop map to Qt's? First, I needed to create an OpenGL context using QGLWidget. I made a subclass of QGLWidget so I could implement my own override functions. Here are some of the most notable functions that you'll need from GLUT and their Qt equivalent:

GLUT Qt
void display() void QGLWidget::paintGL()
void reshape() void QGLWidget::resizeGL(int width, int height)
void mouse() void QGLWidget::mousePressEvent(QMouseEvent *event)
void motion() void QGLWidget::mouseMoveEvent(QMouseEvent *event)

Another thing to know is that there isn't glutPostRedisplay() equivalent in Qt so I had to add a QTimer in my subclassed QGLidget and connect the timeout() slot to the paintGL() function to update the OpenGL framebuffer. For those unfamiliar with slots and signals, it's Qt's observer pattern implementation.

While implementing the wave shader, I had to get the time elapsed since the start of the application in order to update the sine function values given to the shader uniform time value. Then I had to create a QElapsedTimer object to get the elapsed time. Using that value, I sent it to the GPU pipeline adding the uniform value using Qt's shader API.

Application Screenshots:

Windows 8, OS X Mountain Lion, and Ubuntu 12.10 in order

Initial attempt at wave shading with no uniform time value updated nor specular/diffuse lighting.

Final version of the wave shader with specular/diffuse lighting and a green color. I combined the fragment/vertex shaders of the specular/diffuse lighting with the wave shader to produce this effect. The green color comes from multiplying the RGB values vector with a vec3(0.5, 1.0, 0.3). You can see the full fragment shader in simplest.frag. The wave shader is wave_shader.vert. 

Final version of the brick shader. The brick shader has default values of red for the brick color and white for the mortar color. I added an options dialog to be able to change these values by setting the uniform values using Qt's API for managing shader programs.

 

blog comments powered by Disqus

Month List

Tag cloud