Sep, 2008

Sangyoon Lee (sjames @ evl.uic.edu)

Electronic Visualization Laboratory

University of Illinois at Chicago

1. Concept and Brief

I started with given face model for this project. Since our model is human head, I thought that it would be nice to have something related to human face. At the very beginning, I envisoned too much or too complex stuff but converged to human face animation at the end. Project requires two vertex shaders and three fragment shaders. I made many of very tiny shaders but as time goes by... all merged into couples.

In this project, I implemented human face animation with one of class approach, morph target (blend shape, relative vertex animation ...). All animation features are done totally on GPU except some data pre-processing. I will explain this later one.

2. Application

Application developed and tested under Mac OSX 10.5 (Intel). Source code and binary is available below

3. Model Data

For the facial animaiton, I used model set from Sigular FaceGen software (www.facegen.com).This software can export various types of facial expression model as obj. I selected total 6 models including neutral shpae (female neutral, smile, phoneme 'a', fear and male type)

- Pre-Processing

Once six obj models ready, we only need one neutral shape model and 5 morph target (delta of vertex position and normal). I made a bit of modification in Bob's obj library code (http://www.evl.uic.edu/rlk/obj/obj.html) so that I can grab all necessary data set in flat file. This file only includes bunch of vector data (three float numbers). Then, I only need to load neutral obj model and import processed data into main application to utilize massive parallel GPU processing units (vertex shader) to morph face. Following shows some part of processed data. (it's just really numbers)

- Morph data loader

Again, this is small variation of Bob's code to embed morph target data into internal vertex buffer object. I will show more details in the following section.

4. Vertex Buffer Object & Per Vertex Attribute

- VBO

VBO is a big chunk of data to hold all necessary vertex data for graphics card. The neat approach of it is that it can increase GPU performance enormously by streaming it at once. Data will sit in video memory so no worry about bus bottleneck as long as those VBO fits to the capacity of video memory. Obj libray uses this very nicely. Here is the storage of such vertex data for GPU morph animaiton.

- Per Vertex Attribute

There are several ways to manipulate vertex on GPU using shader. Per vertex attribute is one of the most simplest solution. It packs user defined data along with common vertex data set. One example we studied in class is to send attribute at the time we send vertex to GPU. Improvement of my work here is to pack this lots of numbers in VBO so that we can stream it instead that CPU send it one by one.

5. GLSL Shader

Shader programming for morph animation is really simple. The first concept of this came from Siggraph 2003 and also published as part of GPU Gems. Originally their implementation is HLSL (Nvidia Cg). The source code is not available but it is fair enough to implement in GLSL from the scratch.

Basically morphing algorithm accumulates difference of vertex postiion from neutral to target shape based on weight on target shape. Normal is interpolated among them. Following shows a part of vertex shader code to compute position and normal.

Another interesting mophing is to use texture uv coordinate to illustrate the idea of texture unwrap. Two dimentional texture image wraps around our 3D head mesh. Since I know whant all number means here, this coordinate value can be customized in vertex shader. I have tested some variation of this by changing morph speed in each vertex such as linear interpolation, delayed start (kind of clipping plane look), delayed sine speed (make it a bit more dynamic). Here is the vertex shader code for this.

- More shaders merged at the end...

As I described in earlier section... During implementation, all separate shaders are conversed into one grand piece. i.e. muti-texturing for gender switching (female to male and reverse). Morph coloring (visualize the amound of morphing in color spectrum per vertex). Tiling (compositor - post processing of render buffer)...

- Texture UV UnWrap Morphing I (front view)

- Texture UV UnWrap Morphing II (side view)

- Render To Texture (Frame buffer post processing. Grid like effect)

7. Lessons

- Trivial bug takes long long time...

In many cases, examples and tutorials only provide code fragment... but in real, we need lot more complex stuff. Sometimes reallly small piece causes painful debugging. One of example I encountered is the difference of texture indexing between OpenGL and GLSL. I remember there was mention about this in class.... I did not pay that much attention to it since I used to OpenGL before... But it took quite a time to fix the bug in may app.

- Tiny piece of code can do many things

Definitely the most amazing stuff in GPU programming is we can make something really cool with simple coding. This is soooo attractive. Event it requires lots of mathmatical consideration but... its reward is much more than the efforts. Looking forward to CUDAing!