Monday, May 24, 2010

OpenGL minimalist program

Sometime I need a minimalist program to start with for doing some experiment in OpenGL using c++. I always loose time searching or writing such minimalist program. So I post one here.



#include <GL/glut.h>

int win_w = 800;
int win_h = 600;

void resize(int w, int h)
{
  win_w = w; win_h = h;
  glViewport(0,0, win_w, win_h);
}

void draw(void)
{
  glClearColor(0.0, 0.0, 0.0, 1.0);
  glClear(GL_COLOR_BUFFER_BIT);

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(80, win_w / (float)win_h, 1.0, 100.0);

  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  glTranslatef(0,0,-2);
  glutSolidTeapot(1.0f);
  glutSwapBuffers();
}

void keyboard(unsigned char key, int x, int y)
{
  glutPostRedisplay ();
}

int main(int argc, char **argv)
{
  /* Set window size and location */
  glutInit(&argc, argv);
  glutInitWindowSize(640, 480);
  glutInitWindowPosition(0, 0);

  /* Select type of Display mode:
  double buffer & RGBA color */
  glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);

  /*Initialize GLUT state */
  glutCreateWindow("OpenGL Tea Pot");
  glutDisplayFunc( draw );
  glutReshapeFunc( resize );
  glutKeyboardFunc ( keyboard );
  glutMainLoop();

  return 0;
}

And to compile it:

g++ main.cc -lGL -lGLU -lglut -o main

Monday, March 15, 2010

ffmpeg & audacity - 5.1 audio to 2.0

There is a feature that is not implemented (yet) in ffmpeg (version 0.5): down-sampling from 5.1 audio to 2.0, that is from surround sound to stereo. When you try it, you get the following error message:

Resampling with input channels greater than 2 unsupported.
Can not resample 6 channels @ 48000 Hz to 2 channels @ 48000 Hz
Which is quite clear.

Apparently, it will be necessary to have a 2 channels audio file as input. This is where Audacity will help us to bypass that problem. Suppose we have a movie file named 'original.ogg' format that embedding a movie stream and a six channels audio stream.

First we have to extract the audio stream from our file with the following command :

ffmpeg -i original.ogg -vn -acodec copy audio5.1.ogg
The '-vn' option switch means that the video stream is ignored and '-acodec copy' means that the encoding will be the same as the input file.

Now we can editing the 'audio5.1.ogg' using Audacity. We can see the six tracks In the editor. According to the vorbis spec, these tracks are ordered with respect to the speaker locations as follow:

  1. front left
  2. center
  3. front right
  4. rear left
  5. rear right
  6. LFE

To have a stereo audio, we have to merge those six tracks to two tracks, actually named left and right (a bit obvious =) ). We can drop the LFE (Low Frequency Effect) track, since this one is a bit useless for a stereo system. Indeed, we have to duplicate the center track, this one is often used for the voices. So it has to be present in both left and right track. That far we have six tracks. We have to merge them by selecting (shift + click) some of them using the Mix and Render command from the Tracks menu. The front left, rear left and center will be merge into the left track, and front right, rear right and center will be merged into the right track.

We end up with two tracks. We still have two set their property: "Left Channel" for the first track and "Right Channel" for the second track. Export the project to audio2.0.ogg, and we have our stereo audio file.

What is left now is to combine this stereo file with the movie file and encode them into a divx file. Here is the command:

ffmpeg -i original.ogg -i audio2.0.ogg -map 0.0:0 -map 1.0:1 \
-vcodec mpeg4 -vtag DIVX -vb 800kb \
-acodec mp2 -ar 44100 -ab 128kb converted.avi

The '-map' options are used to indicate that we are ignoring the audio stream for the first file and that instead we are using the audio stream from the second file. The '-vtag DIVX' is an option to force the file being tagged as divx. Here we are, we have our 5.1 movie convert to a 2.0 one.

Hope that help.

Wednesday, March 3, 2010

Tablet M-ThinLine, wizardpen driver on Debian

I have a M-ThinLine pen tablet and I wanted to use it under my favorite OS, Debian. I summarize here what I did to make it work.

Apparently there is no driver package (yet?) for this tablet in the official Debian repositories. After a long search over the internet, where there are a myriads of installation tutorials but for Ubuntu, I found this project page which look like the most recent driver according to the version. There is a deb package available but unfortunately it has dependencies with some Ubuntu packages. But the driver sources are there.

After downloading the file 'wizardpen-0.7.0-alpha2.tar.gz', within the archive you will find enough information in the 'INSTALL' file to compile and install the driver. There is an another file 'README-XOrgConfig' for configuring the X-server so it recognizes the tablet. I followed the "HAL-based hotplugging" configuration, but this one did not work for me. So I edited the 'xorg.conf' file, which is a more straightforward way I think.

In the ServerLayout section , you have to add the line [InputDevice "WizardPen Tablet" "AlwaysCore"], so this section should look like this:

Section "ServerLayout"
Identifier     "Layout0"
Screen      0  "Screen0" 0 0
InputDevice    "Keyboard0" "CoreKeyboard"
InputDevice    "Mouse0" "CorePointer"
InputDevice    "WizardPen Tablet" "AlwaysCore"
EndSection

And you have to create a new InputDevice section:

Section "InputDevice"
Identifier      "WizardPen Tablet"
Option          "SendCoreEvents"        "true"
Driver          "wizardpen"
Option          "Name"          "UC-LOGIC Tablet WP5540U"
Option          "Device"        "/dev/input/by-id/usb-UC-LOGIC_Tablet_WP5540U-event-mouse"
Option          "TopX"          "2262"
Option          "TopY"          "3794"
Option          "BottomX"       "30363"
Option          "BottomY"       "30265"
Option          "MaxX"          "30363"
Option          "MaxY"          "30265"
Option          "TopZ"          "0"
Option          "BottomZ"       "1024"
EndSection

You can obtain the name by typing 'grep -i name /proc/bus/input/devices'. The TopX/Y and BottomX/Y can be obtained by running the calibration tool 'wizardpen-calibrate', which is located in the 'calibrate' directory. In order to enable the pen pressure, you have to add the TopZ and BottomZ option, the current value correspond to the maximum range but you can tweak it at will.

Happy pen tablet installation!

Wednesday, November 4, 2009

Grandpa troll

grandpa troll - texturedThis is a model I made from a little grandpa troll statue. First I took digital pictures of the statue from strategic view: front, left and top. Then scale the pictures so the model has the same size from the different views. All the views were merge into a following single picture which I used as reference for the modeling. grandpa troll references pictureAnd here is the topology of the head. grandpa troll wireframe

Tuesday, July 7, 2009

Skeletal animation, Blender and math... continue

In a preview post, I have written about my 3d engine and skeleton animation. My goal was to export an animation from Blender (2.49) and play it back into an another program. This is achieved now and works correctly.

But I have met problems because I misunderstood the different coordinate spaces involved and how they are related to each other in Blender. When you understand those coordinate spaces, a big part of the game consist of using the good maths to build back the animation.

Let's explore the blender skeletal animation system with a special focus on the different coordinate spaces. When you know/understand the needed informations, you can export them by using the Blender Python API.

Armature

An armature is a hierarchal set of bones. One bone can have several children. One bone has none or one parent. The picture below shows two bones. The top one and the bottom one are respectively the child and the parent . This is indicated by the dashed line. A bone can be connected or not to its parent. Connected means that the child's head is at the same position of the parent's tail, and it will remains as this while editing. This feature is useful while editing the armature for structure as arms or spine. But as we are not interested in editing but playing back the animation, this information is not important.

Bone anatomy

The picture below shows one bone in edit mode. A bone is composed of two points, the head and the tail, represented by the spheres, respectively at the bottom and the top of the bone. There are other parameters that characterize a bone, but I would like to focus on those.

In Blender, when you had an armature into a 3d scene (Shift A, Add > Armature), you obtain one bone of one unit length pointing in the world z-axis, as in the picture above. So far, problems arise, and it is about he bone axis... thus the bone space.

The bone space

When you enable bone axis drawing in the Armature tab from the editing panel (F9), you notice that the bone axis (in white) are not align with the world axis (red, blue, and green). And that is very disturbing at first sight because of this counter-intuitive aspect.

The picture above shows the same bone but in pose mode. By looking the transform properties floating panel you notice that the bone has not been rotated (RotX/Y/Z is 0). Hmmm, so, why the bone axis are not aligned with the world axis? Because bone are really typical object in Blender. They are different from other objects such as mesh, camera, or light, about how local axis is defined.

When you edit an armature, you are basically defining bones hierarchy and placing points as bone heads and bone tails. As a bone is defined by two points, you can not tell how a bone is rotated. Until a convention is defined.

The convention used in blender is as followed:
  • The Y axis is aligned along the bone length, that is the normalized vector formed by the head and tail points.
  • The X and Z axis has the same coordinates as Y, but rotated. That is X=(Yy, Yz, Yx), Z=(Yz, Yx, Yy).
  • A rotation angle around the Y axis is defined. Called "Roll" in the properties panel in edit mode.
X, Y, Z formed the bone space. Which is important for the animation because as you will see in the next chapter, the transformations are expressed in that space.

For this purpose, the essential information about the structure of the armature are, for each bone:
  • its name
  • the name of its parent (if it has one)
  • its transform matrix in armature space
  • its rotation matrix in bone space

Animation curves

The picture below is a screen-shot of the Ipo Curve Editor displaying pose curves of one bone. This is visible by selecting "Pose" from the "Ipo Type" combo-box. Here again, you can see that bones are very specific.

Compared with Object Ipo Curves, Bone Ipo Curves are very basic. The ten curves concern "only" the three transformations: translation (LocX, LocY, LocZ), rotation (QuatW, QuatX, QuatY, QuatZ), and scaling (ScaleX, ScaleY, ScaleZ). Notice that quarternion are used for rotation, that's why the x,y,z values vary between 0 and 1, and w between -1 and 1.

One important point to note down for later : those transformations are expressed in bone space.

The skin

The aim of skeletal animation is to deform a skin by moving bones. The skin is often a mesh which is a bunch of connected vertices forming edges and faces. When a bone moves, it also moves the vertices associated to it, thus the skin.

In Blender, bones and vertex groups are associated when they have the same name.

The picture above illustrates the association of a skin and a skeleton. On the left the Outliner Window shows two Vertex Groups named "bottom" and "top", the latter is selected. One the right the 3D Window, in Weight Paint mode, shows the Vertex Groups "bottom" and "top" respectively in blue and red. The armature with the bone names are displayed.

The vertex coordinates of the mesh are expressed in the object space.

The animation: the all together

We have seen all the elements involved in skeletal animation. Let's resume all the informations we can retrieve by the Blender Python API.
  • The skin: the vertex coordinates in object space
  • The skeleton: the bones hierarchy and transform matrices in armature space and in bone space
  • The bone animation curves in bone space
  • The vertexgroups

The skin and the skeleton is either in bind pose or current pose (see this presentation for explanation of those poses). The armature and the mesh are exported in bind pose. The goal is to compute the vertex positions of the mesh in current pose.

Let v the position of a vertex in bind pose in object space and v' its position in current pose. We know v and we have to compute v'.

As the animation curves are expressed in bone space, we need the vertex position from object space v in that space. This is done by multiplying the vertex position in object space v by the inverse of transform matrix in armature space B of the bone b associated with the vertex.

v_bonespace = inv(B_b)v

Then, we multiply this by the transform matrix P_b computed from the animation curves of the bone b. We obtain v' in bone space.

v'_bonespace = P_bv_bonespace

What is left now, is to compute back that position in the armature space. For this we multiply it by the matrix product of rotation and translation of each bone in current pose, from the bone of interest to the root bone. That's it =).

Saturday, July 4, 2009

Skeletal animation, Blender and math

I am implementing a basic graphic engine. So far the engine can, briefly, load textured 3d models from an OBJ files and render them. I am making this engine with the idea of making an abstraction layer over OpenGL in order to manipulate 3d objects as simply as possible...

Now, I am adding skeletal animation to the engine. I have created a python script to export an armature and its animation from Blender into a home-made-OBJ-like-formated file (OBJ does not support animation). The engine can load that file, so an armature can be attached to a mesh in order to deform the latter. I broke my teeth implementing the skeletal animation and get lost into the maths. As a result, I obtained distorted animation, far from satisfying.

Thus, I decided wisely to learn about the math around skeleton animation. After some searches, I have found a very interesting presentation from a video game programming course in which all the maths I need were in, described concisely. I suggest to read this presentation to anyone who want to know about skeletal animation from a mathematical point of view. It is really crystal clear, as I like. Thanks to Jason Gregory.

Monday, June 15, 2009

Island

One animation I have made for fun using the 3d software suite Blender. The music is from the Impossible Mission original TV series.

The crab is animated as one block, without armature. By looking at it you will noticed that any part of its body does not move independently.

The water splashes are made by using the Blender particles system. It looks more as smoke than as water. I should take more time on that if I had to do it again.