Imagination PowerVR SDK Blog

iPhone and matrix palettes


#1

i am able to render the green guy from the skinning example in my current code base, however the pod files my artists are giving me (exported from maya) are not. the bone batch count is > 8 which means the program bonks when i try to render with matrix palettes on the iphone device. is there an export setting or is there something maya specific that needs to be done?


#2

i would add that everything renders correctly in the emulator. i believe the bonk is the result of more than 8 matrix palettes on the iphone hardware.


#3

I think the POD exporter has an option to break up your model into different parts to handle more than whatever hardware limit you are facing in terms of available matrix palettes.


It is all done more-less automatically (bone batches) …



#4

thank you for the reply. i was able to get skinning working on the device by changing the export settings to the following:











rendering is fine on the emulator and but on the iphone it has visual weirdness going on:











below is the rendering code, almost exactly the same as the skinning example. does anyone have any insight into this?





void PVRShot::DrawActor(PVRActor * actor)


{


     CPVRTModelPOD * pModel = actor->GetMesh()->GetModel();


     


     glEnableClientState(GL_VERTEX_ARRAY);


     glEnableClientState(GL_NORMAL_ARRAY);


     glEnableClientState(GL_TEXTURE_COORD_ARRAY);





     for (int iNode = 0; iNode < (int)pModel->nNumMeshNode; ++iNode)


     {


          SPODNode * pNode = &pModel->pNode[iNode];


          SPODMesh * pMesh = &pModel->pMesh[pNode->nIdx];





          glBindBuffer(GL_ARRAY_BUFFER, actor->GetMesh()->GetVertexBuffer()[pNode->nIdx]);


          glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, actor->GetMesh()->GetIndexBuffer()[pNode->nIdx]);





          PVRTexture * pTex = actor->GetMesh()->GetTextures()[pNode->nIdxMaterial];





          if (pTex != NULL)


          {


               glBindTexture(GL_TEXTURE_2D, pTex->GetTexId());





               SPODMaterial * pMat = &pModel->pMaterial[pNode->nIdxMaterial];





               myglMaterialv(GL_FRONT_AND_BACK, GL_AMBIENT, PVRTVec4(pMat->pfMatAmbient, f2vt(1.0f)).ptr());


               myglMaterialv(GL_FRONT_AND_BACK, GL_DIFFUSE, PVRTVec4(pMat->pfMatDiffuse, f2vt(1.0f)).ptr());


          }





          bool bSkinning = (pMesh->sBoneWeight.pData != 0);





          glPushMatrix();


          {


               myglMultMatrix(actor->GetTransform().f);





               if (bSkinning)


               {


                    glEnableClientState(GL_MATRIX_INDEX_ARRAY_OES);


                    glEnableClientState(GL_WEIGHT_ARRAY_OES);


               }





               glVertexPointer(pMesh->sVertex.n, VERTTYPEENUM, pMesh->sVertex.nStride, pMesh->sVertex.pData);


               glNormalPointer(VERTTYPEENUM, pMesh->sNormals.nStride, pMesh->sNormals.pData);


               glTexCoordPointer(pMesh->psUVW[0].n, VERTTYPEENUM, pMesh->psUVW[0].nStride, pMesh->psUVW[0].pData);





               if (bSkinning)


               {


                    extensions->glMatrixIndexPointerOES(pMesh->sBoneIdx.n, GL_UNSIGNED_BYTE, pMesh->sBoneIdx.nStride, pMesh->sBoneIdx.pData);


                    extensions->glWeightPointerOES(pMesh->sBoneWeight.n, VERTTYPEENUM, pMesh->sBoneWeight.nStride, pMesh->sBoneWeight.pData);


               }





               int nStrip = 0;


               int nOffset = 0;





               for (int iBatch = 0; iBatch < pMesh->sBoneBatches.nBatchCnt; ++iBatch)


               {


                    if (bSkinning)


                    {


                         glEnable(GL_MATRIX_PALETTE_OES);


                         glMatrixMode(GL_MATRIX_PALETTE_OES);





                         PVRTMat4 mBone;


                         int nNodeId;


                         const int nCount = pMesh->sBoneBatches.pnBatchBoneCnt[iBatch];





                         for (int j = 0; j < nCount; ++j)


                         {


                              extensions->glCurrentPaletteMatrixOES(j);





                              nNodeId = pMesh->sBoneBatches.pnBatches[iBatch * pMesh->sBoneBatches.nBatchBoneMax + j];


                              pModel->GetBoneWorldMatrix(mBone, *pNode, pModel->pNode[nNodeId]);





                              myglLoadMatrix((camera->GetTransform() * actor->GetTransform() * mBone).f);


                         }


                    }


                    else


                    {


                         glDisable(GL_MATRIX_PALETTE_OES);


                    }





                    glMatrixMode(GL_MODELVIEW);





                    int nTris;





                    if (iBatch + 1 < pMesh->sBoneBatches.nBatchCnt)


                    {


                         nTris = pMesh->sBoneBatches.pnBatchOffset[iBatch + 1] - pMesh->sBoneBatches.pnBatchOffset[iBatch];


                    }


                    else


                    {


                         nTris = pMesh->nNumFaces - pMesh->sBoneBatches.pnBatchOffset[iBatch];


                    }





                    if (pMesh->nNumStrips == 0)


                    {


                         glDrawElements(GL_TRIANGLES, nTris * 3, GL_UNSIGNED_SHORT, &((unsigned short *)0)[3 * pMesh->sBoneBatches.pnBatchOffset[iBatch]]);


                    }


                    else


                    {


                         int nTrisDrawn = 0;





                         while (nTrisDrawn < nTris)


                         {


                              glDrawElements(GL_TRIANGLE_STRIP, pMesh->pnStripLength[nStrip] + 2, GL_UNSIGNED_SHORT, &((GLshort *)0)[nOffset]);





                              nOffset += pMesh->pnStripLength[nStrip] + 2;


                              nTrisDrawn += pMesh->pnStripLength[nStrip];


                              


                              ++nStrip;


                         }


                    }


               }





               if (bSkinning)


               {


                    glDisableClientState(GL_MATRIX_INDEX_ARRAY_OES);


                    glDisableClientState(GL_WEIGHT_ARRAY_OES);





                    glDisable(GL_MATRIX_PALETTE_OES);


               }


          }


          glPopMatrix();


     }





     glDisableClientState(GL_VERTEX_ARRAY);


     glDisableClientState(GL_NORMAL_ARRAY);


     glDisableClientState(GL_TEXTURE_COORD_ARRAY);





     glBindBuffer(GL_ARRAY_BUFFER, 0);


     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);


}



#5

the image links aren’t working.





the image showing the maya exporter settings:


http://img160.yfrog.com/i/pvrpod.png/





the image showing rendering weirdness:


http://img159.yfrog.com/i/20100105113338.jpg/


#6

the above code correctly renders the man_float.pod from the skinning example. it is only with the pods that my artists export that this problem occurs.


#7

It is hard to say what is going on given a static blurry image…





I am not even sure what is wrong there … the gun is not positioned correctly ?



#8

there is no gun, it is a boxer


#9

Ah ok … it looks like parts of glove geometry don’t have weights assigned to them ( and thus are not being transformed )



#10

this has been resolved. it was a maya/export problem. this is my artists explanation:





As most people are aware, the iphone can only handle a max of 3 bone influences. Shaman however, can correctly display boned meshes with up to 4 inlfuences, which creates a disconnect between what you see in the previewer and the actual device.


To properly export a boned, skinned, and animated 3d mesh that works on the device, follow these rules:





1) You cannot use a straight rigid bind. It will not animate.


2) When binding the skeleton to the mesh, use a max bone influence of 3. Do not maintain max influences after bind.


3) When exporting, use these settings:





     X Export Geometry


     X Export materials


     - Fixed point


     


     X Export controllers


     


     OpenGL     





     X Normals


     - Vertex colours


     X Mapping CHannels


     - Flip V


     - Generate tangent-space


     X Interleave vectors


     X Export Matrices





     X Export skin modifiers


          MAx matrices: 8





     Triangle strips


          X Indexed





     PVRTGeometrySort


          X Sort vertices





Under Vertex vector formats, change Bone indices to ‘unsigned byte’ and uncheck the box under ‘a3’. Leave Bone weights as ‘float’ and uncheck the box under ‘a3’. Your UVW settings may need to change based on your situation, but generally, you wont need UVW2 and up, so uncheck all the boxes for those. For UVW0 and 1, uncheck the boxes under ‘a2’.





This should produce a working model for the device, tweak as neccesary for your needs.