IT tutorials
 
Mobile
 

iphone 3D Programming : Optimizing Animation with Vertex Skinning (part 2)

11/15/2012 3:45:42 PM
- Free product key for windows 10
- Free Product Key for Microsoft office 365
- Malwarebytes Premium 3.7.1 Serial Keys (LifeTime) 2019

3. Skinning with OpenGL ES 1.1

All Apple devices at the time of this writing support the GL_OES_matrix_palette extension under OpenGL ES 1.1. As you’ll soon see, it works in a manner quite similar to the OpenGL ES 2.0 method previously discussed. The tricky part is that it imposes limits on the number of so-called vertex units and palette matrices.

Each vertex unit performs a single bone transformation. In the simple stick figure example, we need only two vertex units for each joint, so this isn’t much of a problem.

Palette matrices are simply another term for bone matrices. We need 17 matrices for our stick figure example, so a limitation might complicate matters.

Here’s how you can determine how many vertex units and palette matrices are supported:

int numUnits;
glGetIntegerv(GL_MAX_VERTEX_UNITS_OES, &numUnits);

int maxMatrices;
glGetIntegerv(GL_MAX_PALETTE_MATRICES_OES, &maxMatrices); 

Table 1 shows the limits for current Apple devices at the time of this writing.

Table 1. Matrix palette limitations
Apple deviceVertex unitsPalette matrices
First-generation iPhone and iPod touch39
iPhone 3G and 3GS411
iPhone Simulator411

Uh oh, we need 17 matrices, but at most only 11 are supported! Fret not; we can simply split the rendering pass into two draw calls. That’s not too shoddy! Moreover, since glDrawElements allows us to pass in an offset, we can still store the entire stick figure in only one VBO.

Let’s get down to the details. Since OpenGL ES 1.1 doesn’t have uniform variables, it supplies an alternate way of handing bone matrices over to the GPU. It works like this:

glEnable(GL_MATRIX_PALETTE_OES);
glMatrixMode(GL_MATRIX_PALETTE_OES);
for (int boneIndex = 0; boneIndex < boneCount; ++boneIndex) {
    glCurrentPaletteMatrixOES(boneIndex);
    glLoadMatrixf(modelviews[boneIndex].Pointer());
}

That was pretty straightforward! When you enable GL_MATRIX_PALETTE_OES, you’re telling OpenGL to ignore the standard model-view and instead use the model-views that get specified while the matrix mode is set to GL_MATRIX_PALETTE_OES.

We also need a way to give OpenGL the blend weights and bone indices. That is simple enough:

glEnableClientState(GL_WEIGHT_ARRAY_OES);
glEnableClientState(GL_MATRIX_INDEX_ARRAY_OES);

glMatrixIndexPointerOES(2, GL_UNSIGNED_BYTE, stride, 
                        _offsetof(Vertex, BoneIndices));
glWeightPointerOES(2, GL_FLOAT, stride, _offsetof(Vertex, BoneWeights));

We’re now ready to write some rendering code, taking into account that the number of supported matrix palettes might be less than the number of bones in our model. Check out Example 5 to see how we “cycle” the available matrix slots; further explanation follows the listing.

Example 5. ES 1.1 Render method for vertex skinning
const SkinnedFigure& figure = m_skinnedFigure;

// Set up for skinned rendering:
glMatrixMode(GL_MATRIX_PALETTE_OES);
glEnableClientState(GL_WEIGHT_ARRAY_OES);
glEnableClientState(GL_MATRIX_INDEX_ARRAY_OES);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, figure.IndexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, figure.VertexBuffer);

glMatrixIndexPointerOES(2, GL_UNSIGNED_BYTE, stride, 
                        _offsetof(Vertex, BoneIndices));
glWeightPointerOES(2, GL_FLOAT, stride, _offsetof(Vertex, BoneWeights));
glVertexPointer(3, GL_FLOAT, stride, _offsetof(Vertex, Position));
glTexCoordPointer(2, GL_FLOAT, stride, _offsetof(Vertex, TexCoord));


// Make several rendering passes if need be, // depending on the maximum bone count: int startBoneIndex = 0; while (startBoneIndex < BoneCount - 1) { int endBoneIndex = min(BoneCount, startBoneIndex + m_maxBoneCount); for (int boneIndex = startBoneIndex; boneIndex < endBoneIndex; ++boneIndex) { int slotIndex; // All passes beyond the first pass are offset by one. if (startBoneIndex > 0) slotIndex = (boneIndex + 1) % m_maxBoneCount; else slotIndex = boneIndex % m_maxBoneCount; glCurrentPaletteMatrixOES(slotIndex); mat4 modelview = figure.Matrices[boneIndex]; glLoadMatrixf(modelview.Pointer()); } size_t indicesPerBone = 12 + 6 * (NumDivisions + 1); int startIndex = startBoneIndex * indicesPerBone; int boneCount = endBoneIndex - startBoneIndex; const GLvoid* byteOffset = (const GLvoid*) (startIndex * 2); int indexCount = boneCount * indicesPerBone; glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_SHORT, byteOffset); startBoneIndex = endBoneIndex - 1; }

Under our system, if the model has 17 bones and the hardware supports 11 bones, vertices affected by the 12th matrix should have an index of 1 rather than 11; see Figure 3 for a depiction of how this works.

Figure 3. Rendering a 17-bone system on 11-bone hardware


Unfortunately, our system breaks down if at least one vertex needs to be affected by two bones that “span” the two passes, but this rarely occurs in practice.

4. Generating Weights and Indices

The limitation on available matrix palettes also needs to be taken into account when annotating the vertices with their respective matrix indices. Example 6 shows how our system generates the blend weights and indices for a single limb.

Example 6. Generation of bone weights and indices
for (int j = 0; j < NumSlices; ++j) {
    
    GLushort index0 = floor(blendWeight);
    GLushort index1 = ceil(blendWeight);
    index1 = index1 < BoneCount ? index1 : index0;
    
    int i0 = index0 % maxBoneCount;
    int i1 = index1 % maxBoneCount;
    
    // All passes beyond the first pass are offset by one.
    if (index0 >= maxBoneCount || index1 >= maxBoneCount) {
        i0++;
        i1++;
    }
    
    destVertex->BoneIndices = i1 | (i0 << 8);
    destVertex->BoneWeights.x = blendWeight - index0;
    destVertex->BoneWeights.y = 1.0f - destVertex->BoneWeights.x;
    destVertex++;
    
    destVertex->BoneIndices = i1 | (i0 << 8);
    destVertex->BoneWeights.x = blendWeight - index0;
    destVertex->BoneWeights.y = 1.0f - destVertex->BoneWeights.x;
    destVertex++;

    blendWeight += (j < NumSlices / 2) ? delta0 : delta1;
}

					  

In Example 6, the delta0 and delta1 variables are the increments used for each half of limb; refer to Table 2 and flip back to Figure 2 to see how this works.

Table 2. Bone weight increments
LimbIncrement
First half of upper arm0
Second half of upper arm0.166
First half of forearm0.166
Second half of forearm0

For simplicity, we’re using a linear falloff of bone weights here, but I encourage you to try other variations. Bone weight distribution is a bit of a black art.

5. Watch Out for Pinching

Before you get too excited, I should warn you that vertex skinning isn’t a magic elixir. An issue called pinching has caused many a late night for animators and developers. Pinching is a side effect of interpolation that causes severely angled joints to become distorted (Figure 3).

Figure 3. Pinching


If you’re using OpenGL ES 2.0 and pinching is causing headaches, you should research a technique called dual quaternion skinning, developed by Ladislav Kavan and others.
 
Others
 
- iphone 3D Programming : Optimizing Animation with Vertex Skinning (part 1)
- Windows Phone 7 : Using the MediaElement Control to Play Both Music and Video
- Windows Phone 7 : User Interface - Using Launchers and Choosers
- jQuery 1.3 : Simple events - A simple style switcher & Shorthand events
- jQuery 1.3 : Events - Performing tasks on page load
- iPhone Application Development : Creating Rotatable and Resizable Interfaces with Interface Builder
- iPhone Application Development : Rotatable and Resizable Interfaces
- Mapping Well-Known Patterns onto Symbian OS : Handle–Body
- Mapping Well-Known Patterns onto Symbian OS : Adapter
- Mobile Web Apps : Loading Pages (part 3) - Going Backwards
 
 
Top 10
 
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 2) - Wireframes,Legends
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 1) - Swimlanes
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Formatting and sizing lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Adding shapes to lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Sizing containers
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 3) - The Other Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 2) - The Data Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 1) - The Format Properties of a Control
- Microsoft Access 2010 : Form Properties and Why Should You Use Them - Working with the Properties Window
- Microsoft Visio 2013 : Using the Organization Chart Wizard with new data
Technology FAQ
- Is possible to just to use a wireless router to extend wireless access to wireless access points?
- Ruby - Insert Struct to MySql
- how to find my Symantec pcAnywhere serial number
- About direct X / Open GL issue
- How to determine eclipse version?
- What SAN cert Exchange 2010 for UM, OA?
- How do I populate a SQL Express table from Excel file?
- code for express check out with Paypal.
- Problem with Templated User Control
- ShellExecute SW_HIDE
programming4us programming4us