# Difference between revisions of "Skeletal Animation"

(Downloads url site no longer exists. Removed.) |
|||

(8 intermediate revisions by 5 users not shown) | |||

Line 1: | Line 1: | ||

− | This document will talk about doing skeletal based animation but it will be brief since the subject is complex and there are also other sources (websites and books and | + | This document will talk about doing skeletal based animation but it will be brief since the subject is complex and there are also other sources (websites and books and demos at http://developer.nvidia.com in the SDK, the tutorial [http://voxels.blogspot.com/2014/03/skinned-skeletal-animation-tutorial.html here].<br> |

You would need to model the object or human or animal in the software of your choice and export it in the file format of your choice.<br> | You would need to model the object or human or animal in the software of your choice and export it in the file format of your choice.<br> | ||

<br> | <br> | ||

Line 16: | Line 16: | ||

Let's assume our entire model will have 10 bones. Let's assume each vertex will have 2 bones.<br> | Let's assume our entire model will have 10 bones. Let's assume each vertex will have 2 bones.<br> | ||

So your vertex structure would look something like this :<br> | So your vertex structure would look something like this :<br> | ||

− | + | <source lang="c"> | |

− | + | struct MyVertex | |

− | float x, y, z; //Vertex | + | { |

− | float nx, ny, nz; //Normal | + | float x, y, z; // Vertex |

− | float s0, t0; //Texcoord | + | float nx, ny, nz; // Normal |

− | float index0, index1; //Index into the bone/offset matrix array | + | float s0, t0; // Texcoord |

− | float weight0, weight1; //The blend factor for each bone/offset matrix | + | float index0, index1; // Index into the bone/offset matrix array (2 bones) |

− | + | float weight0, weight1; // The blend factor for each bone/offset matrix (2 bones) | |

+ | }; | ||

+ | </source> | ||

You would be boning your vertex and normals. The texcoords just pass through.<br> | You would be boning your vertex and normals. The texcoords just pass through.<br> | ||

If you have tangent vectors, you would bone them as well.<br> | If you have tangent vectors, you would bone them as well.<br> | ||

<b>Warning : notice that each bone matrix will consume a lot of register space on the GPU. Each matrix takes 4 registers.</b><br> | <b>Warning : notice that each bone matrix will consume a lot of register space on the GPU. Each matrix takes 4 registers.</b><br> | ||

+ | Since our example will have 10 bones (mat4), that makes 40 registers (vec4), which isn't really a problem for any GPU but typically, your model may have way more bones, perhaps 200 bones.<br> | ||

Instead of uploading a mat4 for each bone, upload a pair of quaternion and offset. A quat uses a vec4 and offset uses a vec4.<br> | Instead of uploading a mat4 for each bone, upload a pair of quaternion and offset. A quat uses a vec4 and offset uses a vec4.<br> | ||

As a result, you'll cut the register need of your shader in half.<br> | As a result, you'll cut the register need of your shader in half.<br> | ||

Of course, your would have to convert them to a mat4 in your shader which will cost you a few clock cycles.<br> | Of course, your would have to convert them to a mat4 in your shader which will cost you a few clock cycles.<br> | ||

Here, we'll use a mat4 matrix.<br> | Here, we'll use a mat4 matrix.<br> | ||

+ | Notice that in the shader example unlike the examples on the other Wiki pages, we aren't using any built in features of GL. We aren't using gl_Vertex, gl_MultiTexCoord0, ftransform(), gl_ProjectionModelViewMatrix, gl_Normal, etc. We are using our own attribute names and our own varying and our own uniforms. | ||

− | + | <source lang="glsl"> | |

− | + | // Vertex Shader | |

− | + | attribute vec4 Vertex; | |

− | + | attribute vec3 Normal; | |

− | + | attribute vec2 TexCoord; | |

− | + | attribute vec2 Index; | |

− | + | attribute vec2 Weight; | |

− | + | uniform mat4 ModelviewMatrix; | |

− | + | uniform mat4 ProjectionModelviewMatrix; | |

− | + | uniform mat4 Bone[10]; // Array of bones that you compute (animate) on the CPU and you upload to the shader | |

− | + | // -------------------- | |

− | + | varying vec2 TexCoord0; | |

− | + | varying vec3 EyeNormal; | |

− | + | // -------------------- | |

− | + | void main() | |

+ | { | ||

vec4 newVertex; | vec4 newVertex; | ||

vec4 newNormal; | vec4 newNormal; | ||

int index; | int index; | ||

− | // | + | // -------------------- |

− | index=int(Index.x); | + | index=int(Index.x); // Cast to int |

newVertex = (Bone[index] * Vertex) * Weight.x; | newVertex = (Bone[index] * Vertex) * Weight.x; | ||

newNormal = (Bone[index] * vec4(Normal, 0.0)) * Weight.x; | newNormal = (Bone[index] * vec4(Normal, 0.0)) * Weight.x; | ||

− | index=int(Index.y); | + | index=int(Index.y); //Cast to int |

newVertex = (Bone[index] * Vertex) * Weight.y + newVertex; | newVertex = (Bone[index] * Vertex) * Weight.y + newVertex; | ||

newNormal = (Bone[index] * vec4(Normal, 0.0)) * Weight.y + newNormal; | newNormal = (Bone[index] * vec4(Normal, 0.0)) * Weight.y + newNormal; | ||

Line 61: | Line 66: | ||

gl_Position = ProjectionModelviewMatrix * newVertex; | gl_Position = ProjectionModelviewMatrix * newVertex; | ||

TexCoord0 = TexCoord; | TexCoord0 = TexCoord; | ||

− | + | } | |

+ | </source> | ||

+ | |||

+ | Now that you have studied the code above, what's the problem?<br> | ||

+ | <source lang="glsl"> | ||

+ | gl_Position = ProjectionModelviewMatrix * newVertex; | ||

+ | </source> | ||

+ | |||

+ | There is a risk that newVertex.w might not be exactly 1.0. Just to be safe | ||

+ | <source lang="glsl"> | ||

+ | gl_Position = ProjectionModelviewMatrix * vec4(newVertex.xyz, 1.0); | ||

+ | </source> | ||

+ | |||

+ | [[Category:Rendering Techniques]] | ||

+ | [[Category:Algorithm]] |

## Latest revision as of 19:57, 24 August 2018

This document will talk about doing skeletal based animation but it will be brief since the subject is complex and there are also other sources (websites and books and demos at http://developer.nvidia.com in the SDK, the tutorial here.

You would need to model the object or human or animal in the software of your choice and export it in the file format of your choice.

Here is a description of one way to do it :

1. Your object will be in a default pose.

2. All the vertices are in their respective places.

3. You have an array of bones.

3. You have an array of offsets.

4. What's a bone? It is a rotation matrix. You only need a 3x3 matrix.

5. What's an offset? It is a XYZ value you use to translate your vertex.

6. A bone and its offset together make a 4x4 matrix.

7. Each vertex can have a certain amount of bones that influence it. 0, 1, 2, ...you name it!

8. For each bone that influences your vertex, you need to decide how much it influences. This is called a weight or blend factor. 1 weight per bone/offset matrix

9. In order to animate your object, you need to change the bones and offset matrix. Normally, you would not change the weights.

Let's assume our entire model will have 10 bones. Let's assume each vertex will have 2 bones.

So your vertex structure would look something like this :

```
struct MyVertex
{
float x, y, z; // Vertex
float nx, ny, nz; // Normal
float s0, t0; // Texcoord
float index0, index1; // Index into the bone/offset matrix array (2 bones)
float weight0, weight1; // The blend factor for each bone/offset matrix (2 bones)
};
```

You would be boning your vertex and normals. The texcoords just pass through.

If you have tangent vectors, you would bone them as well.

**Warning : notice that each bone matrix will consume a lot of register space on the GPU. Each matrix takes 4 registers.**

Since our example will have 10 bones (mat4), that makes 40 registers (vec4), which isn't really a problem for any GPU but typically, your model may have way more bones, perhaps 200 bones.

Instead of uploading a mat4 for each bone, upload a pair of quaternion and offset. A quat uses a vec4 and offset uses a vec4.

As a result, you'll cut the register need of your shader in half.

Of course, your would have to convert them to a mat4 in your shader which will cost you a few clock cycles.

Here, we'll use a mat4 matrix.

Notice that in the shader example unlike the examples on the other Wiki pages, we aren't using any built in features of GL. We aren't using gl_Vertex, gl_MultiTexCoord0, ftransform(), gl_ProjectionModelViewMatrix, gl_Normal, etc. We are using our own attribute names and our own varying and our own uniforms.

```
// Vertex Shader
attribute vec4 Vertex;
attribute vec3 Normal;
attribute vec2 TexCoord;
attribute vec2 Index;
attribute vec2 Weight;
uniform mat4 ModelviewMatrix;
uniform mat4 ProjectionModelviewMatrix;
uniform mat4 Bone[10]; // Array of bones that you compute (animate) on the CPU and you upload to the shader
// --------------------
varying vec2 TexCoord0;
varying vec3 EyeNormal;
// --------------------
void main()
{
vec4 newVertex;
vec4 newNormal;
int index;
// --------------------
index=int(Index.x); // Cast to int
newVertex = (Bone[index] * Vertex) * Weight.x;
newNormal = (Bone[index] * vec4(Normal, 0.0)) * Weight.x;
index=int(Index.y); //Cast to int
newVertex = (Bone[index] * Vertex) * Weight.y + newVertex;
newNormal = (Bone[index] * vec4(Normal, 0.0)) * Weight.y + newNormal;
EyeNormal = vec3(ModelviewMatrix * newNormal);
gl_Position = ProjectionModelviewMatrix * newVertex;
TexCoord0 = TexCoord;
}
```

Now that you have studied the code above, what's the problem?

```
gl_Position = ProjectionModelviewMatrix * newVertex;
```

There is a risk that newVertex.w might not be exactly 1.0. Just to be safe

```
gl_Position = ProjectionModelviewMatrix * vec4(newVertex.xyz, 1.0);
```