天行健 君子当自强而不息

【ZT】模拟实现ID3DXSkinInfo::UpdateSkinnedMesh

原文出处:http://blog.csdn.net/cywater2000/archive/2006/01/05/571299.aspx

一.公式:

FinalPos = MeshPos + ∑( Difference_i * Weight_i)

= MeshPos + ∑( (NewMeshPos_i - MeshPos) * Weight_i )

= MeshPos + ∑( (MeshPos × OffsetMatix_i × CombinedMatrix_i - MeshPos) * Weight_i ) [1]


其中:

MeshPos:                  某顶点在mesh中的原始位置

NewMeshPos_i:         此顶点受某骨骼i影响后变换到的新位置

Difference_i:              两者之间的位移差值

Weight_i::                  此顶点受某骨骼i的影响权重

OffsetMatix_i:            骨骼i的偏移矩阵

CombinedMatrix_i:       骨骼i经过层次更新后的混合矩阵

∑:                              求和(对所有影响该顶点的骨骼)

FinalPos:                    此顶点的最终位置

 

法线计算同理。

 

二.模拟代码(没有优化):


HRESULT UpdateSkinnedMesh(ID3DXSkinInfo *pSkinInfo,
                  
const D3DXMATRIX *pBoneTransforms,
                  
const D3DXMATRIX *pBoneInvTransposeTransforms, //not use(原函数也没用)
                  LPCVOID pVerticesSrc,
                  PVOID pVerticesDst,
//注意下面增加的两个变量是原函数在调用时没有的,因为ID3DXSkinInfo的内部机制可以获得
                  DWORD numTotalVerts, 
// 指mesh的顶点个数
                  DWORD dwStride 
// 指mesh每个顶点的间距,即每个顶点结构的大小
                  )
{
    DWORD 
*pVertsIndic = NULL;
    
float *pVertsWeigh = NULL;
    DWORD dwNumVerts;
    DWORD offsetByte;

    BYTE 
*pDest = (BYTE*)pVerticesDst; //目标顶点缓冲
    
const BYTE *pSrc = (BYTE*)pVerticesSrc; //源顶点缓冲

    memcpy(pDest, pSrc, numTotalVerts 
* dwStride);

    
for(DWORD i = 0; i < pSkinInfo->GetNumBones(); i++)
    {
       dwNumVerts 
= pSkinInfo->GetNumBoneInfluences(i); //得到受影响的顶点个数

       
if(dwNumVerts <= 0)
           
continue;

       pVertsIndic 
= new DWORD[dwNumVerts];
       pVertsWeigh 
= new float[dwNumVerts];

       pSkinInfo
->GetBoneInfluence(i, pVertsIndic, pVertsWeigh);

       
while(dwNumVerts--)
       {
           DWORD index 
= pVertsIndic[dwNumVerts]; //当前受影响的顶点索引
           
float weight = pVertsWeigh[dwNumVerts]; //当前受影响顶点的权重

           offsetByte 
= index * dwStride;

           D3DXVECTOR3 vecPos 
= *(D3DXVECTOR3 *)(pSrc + offsetByte); //位置
           D3DXVECTOR3 vecNor 
= *(D3DXVECTOR3 *)(pSrc + offsetByte + sizeof(D3DXVECTOR3)); //法线

           D3DXVECTOR3 vecPos2, vecNor2;
           D3DXVec3TransformCoord(
&vecPos2, &vecPos, &pBoneTransforms[i]);
           D3DXVec3TransformNormal(
&vecNor2, &vecNor, &pBoneTransforms[i]);

           D3DXVECTOR3 
*pV = (D3DXVECTOR3 *)(pDest + offsetByte);
           D3DXVECTOR3 
*pN = (D3DXVECTOR3 *)(pDest + offsetByte + sizeof(D3DXVECTOR3));

           D3DXVECTOR3 diff 
= (vecPos2 - vecPos) * weight;
           
*pV += diff;

           diff 
= (vecNor2 - vecNor) * weight;
           
*pN += diff;
       }

       delete[] pVertsIndic;
       delete[] pVertsWeigh;
    }
 
    
return S_OK;

}

    注意在调用UpdateSkinnedMesh前,pBoneTransforms已经是OffsetMatix与CombinedMatrix的连接矩阵了(ID3DXSkinInfo::UpdateSkinnedMesh也是这么要求的)。

 

重要更新:

骨骼动画属于Geometry Blending,因此标准做法应该是:
 [2]
即FinalPos =∑(NewMeshPos_i  * Weight_i) + NewMeshPos_n * (1 - ∑Weight_i ) , i=0,1..n-1
=∑(MeshPos × OffsetMatix_i × CombinedMatrix_i * Weight_i) + (MeshPos × OffsetMatix_n × CombinedMatrix_n) * (1 - ∑Weight_i ) , i=0,1..n-1 [3]
(显然只有当影响顶点的所有权重之和等于1时,公式[1]与[3]才等价)


posted on 2008-04-22 15:22 lovedday 阅读(1065) 评论(0)  编辑 收藏 引用 所属分类: ■ DirectX 9 Program


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


公告

导航

统计

常用链接

随笔分类(178)

3D游戏编程相关链接

搜索

最新评论