123
This commit is contained in:
168
CryAnimation/CrySkinBasisBuilder.cpp
Normal file
168
CryAnimation/CrySkinBasisBuilder.cpp
Normal file
@@ -0,0 +1,168 @@
|
||||
#include "stdafx.h"
|
||||
#include "CrySkinRigidBasis.h"
|
||||
#include "CrySkinBasisBuilder.h"
|
||||
|
||||
CrySkinBasisBuilder::CrySkinBasisBuilder (const ICrySkinSource* pGeometry, const Matrix44* pMatInvDef, unsigned numBoneInfos):
|
||||
CrySkinBuilderBase0 (pGeometry),
|
||||
m_pMatInvDef(pMatInvDef),
|
||||
m_numBoneInfos (numBoneInfos),
|
||||
m_nDestIntervalBegin (0),
|
||||
m_nDestIntervalEnd (0),
|
||||
m_numBones (0),
|
||||
m_nFirstBone (0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// sets the destination vertex interval to operate on. Initially, this is infinity.
|
||||
// The destination vertex interval is the interval within which the destination vertex
|
||||
// index must lie in order to be skinned. The base of the interval is considered
|
||||
// vertex 0 in the produced skinner
|
||||
void CrySkinBasisBuilder::setDestinationInterval (unsigned nBegin, unsigned nEnd)
|
||||
{
|
||||
if (nEnd > m_pGeometry->numExtTangents())
|
||||
nEnd = m_pGeometry->numExtTangents();
|
||||
|
||||
if (nBegin < nEnd)
|
||||
{
|
||||
m_nDestIntervalBegin = nBegin;
|
||||
m_nDestIntervalEnd = nEnd;
|
||||
|
||||
preprocess();
|
||||
makeBoneBases ();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nDestIntervalBegin = 0;
|
||||
m_nDestIntervalEnd = 0;
|
||||
m_numBones = 0;
|
||||
m_nFirstBone = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// initializes the given rigid basis builder
|
||||
void CrySkinBasisBuilder::initRigidBasisSkin (CrySkinRigidBasis* pSkin)
|
||||
{
|
||||
assert (sizeof(SPipTangentsA16)==0x30);
|
||||
unsigned numAuxInts = 2 * (m_numBones-m_nFirstBone);
|
||||
unsigned numBases = m_nDestIntervalEnd-m_nDestIntervalBegin;
|
||||
pSkin->init (2 * numBases, numAuxInts, m_nFirstBone, m_numBones);
|
||||
|
||||
CrySkinStreams stream, streamBegin, streamEnd;
|
||||
streamBegin.pAux = pSkin->m_arrAux.begin();
|
||||
streamBegin.pVert = pSkin->m_arrVertices.begin();
|
||||
stream = streamBegin;
|
||||
streamEnd.pAux = streamBegin.pAux + numAuxInts;
|
||||
streamEnd.pVert = streamBegin.pVert + 2 * numBases;
|
||||
|
||||
for (unsigned nBone = m_nFirstBone; nBone < m_numBones; ++nBone)
|
||||
{
|
||||
// for each bone, fill the three groups
|
||||
// we fill the left and right vertices
|
||||
fillGroup (stream, m_arrBoneBases[nBone].arrRight);
|
||||
assert (stream.pAux <= streamEnd.pAux);
|
||||
assert (stream.pVert <= streamEnd.pVert);
|
||||
fillGroup (stream, m_arrBoneBases[nBone].arrLeft);
|
||||
// only when we processed the last bone, we should have the pAux pointing to the end
|
||||
assert (stream.pAux <= streamEnd.pAux);
|
||||
assert (stream.pVert <= streamEnd.pVert);
|
||||
}
|
||||
}
|
||||
|
||||
void clipDenormal (float& x)
|
||||
{
|
||||
if (x > -1e-4 && x < 1e-4)
|
||||
x = 0;
|
||||
}
|
||||
|
||||
void clipDenormals(Vec3d& v)
|
||||
{
|
||||
clipDenormal(v.x);
|
||||
clipDenormal(v.y);
|
||||
clipDenormal(v.z);
|
||||
}
|
||||
|
||||
// makes up the basis array
|
||||
void CrySkinBasisBuilder::makeBoneBases ()
|
||||
{
|
||||
const unsigned* pExtToInt = m_pGeometry->getExtToIntMapEntries();
|
||||
|
||||
m_arrBoneBases.clear();
|
||||
m_arrBoneBases.resize (m_numBones);
|
||||
|
||||
unsigned i;
|
||||
// preallocate for push_back
|
||||
for (i = 0; i < m_numBones; ++i)
|
||||
m_arrBoneBases[i].reserve (m_nDestIntervalEnd / m_numBones);
|
||||
|
||||
for (i = m_nDestIntervalBegin; i < m_nDestIntervalEnd; ++i)
|
||||
{
|
||||
unsigned nGeomVert = pExtToInt[i];
|
||||
|
||||
TangData rBasis = m_pGeometry->getExtTangent (i);
|
||||
clipDenormals(rBasis.binormal);
|
||||
clipDenormals(rBasis.tangent);
|
||||
const CryVertexBinding& rLink = m_pGeometry->getLink(nGeomVert);
|
||||
unsigned nBone = rLink[0].BoneID;
|
||||
assert (nBone < m_numBoneInfos);
|
||||
|
||||
CrySkinRigidBasisArray* pTargetArray;
|
||||
if ((rBasis.tangent ^ rBasis.binormal)*rBasis.tnormal > 0)
|
||||
pTargetArray = &m_arrBoneBases[nBone].arrRight;
|
||||
else
|
||||
pTargetArray = &m_arrBoneBases[nBone].arrLeft;
|
||||
|
||||
const Matrix44& matInvDef = m_pMatInvDef[nBone];
|
||||
|
||||
pTargetArray->push_back(CrySkinRigidBaseInfo (matInvDef,rBasis,i-m_nDestIntervalBegin));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// calculate the number of used bones and the skip-bone
|
||||
void CrySkinBasisBuilder::preprocess()
|
||||
{
|
||||
unsigned numTangents = m_pGeometry->numExtTangents();
|
||||
const unsigned* pExtToInt = m_pGeometry->getExtToIntMapEntries();
|
||||
|
||||
m_numBones = 0;
|
||||
m_nFirstBone = 0;
|
||||
bool bNotInited = true;
|
||||
|
||||
for (unsigned i = m_nDestIntervalBegin; i < min(m_nDestIntervalEnd,numTangents); ++i)
|
||||
{
|
||||
unsigned nGeomVert = pExtToInt[i];
|
||||
const CryVertexBinding& rLink = m_pGeometry->getLink(nGeomVert);
|
||||
unsigned nBone = rLink[0].BoneID;
|
||||
|
||||
if (bNotInited)
|
||||
{
|
||||
m_nFirstBone = nBone;
|
||||
m_numBones = nBone+1;
|
||||
bNotInited = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nFirstBone = min (m_nFirstBone, nBone);
|
||||
m_numBones = max (nBone+1, m_numBones);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fills the given bases to the simple stream
|
||||
typedef std::vector< CrySkinRigidBaseInfo > CrySkinRigidBasisArray;
|
||||
void CrySkinBasisBuilder::fillGroup (CrySkinStreams& streams, const CrySkinRigidBasisArray& arrBases)
|
||||
{
|
||||
// the group header is the number of vertices in the group
|
||||
*streams.pAux++ = (CrySkinAuxInt)arrBases.size();
|
||||
|
||||
CrySkinRigidBasisArray::const_iterator it = arrBases.begin(), itEnd = it + arrBases.size();
|
||||
for (; it != itEnd; ++it)
|
||||
{
|
||||
it->build(streams.pVert);
|
||||
streams.pVert += 2;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user