1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "nel/3d/bone.h"
20 #include "nel/3d/anim_ctrl.h"
21 #include "nel/misc/hierarchical_timer.h"
31 // ***************************************************************************
32 // ***************************************************************************
34 // ***************************************************************************
35 // ***************************************************************************
38 static const CVector
UnitScale(1,1,1);
41 // ***************************************************************************
42 CBoneBase::CBoneBase() : DefaultPos(CVector(0,0,0)), DefaultRotEuler(CVector(0,0,0)),
43 DefaultScale(UnitScale
), DefaultPivot(CVector(0,0,0)), SkinScale(UnitScale
)
47 // Default: never disable.
48 LodDisableDistance
= 0.f
;
52 // ***************************************************************************
53 void CBoneBase::serial(NLMISC::IStream
&f
)
61 sint ver
= f
.serialVersion(2);
66 f
.serial(UnheritScale
);
69 f
.serial(LodDisableDistance
);
72 // Default: never disable.
73 LodDisableDistance
= 0.f
;
77 f
.serial(DefaultRotEuler
);
78 f
.serial(DefaultRotQuat
);
79 f
.serial(DefaultScale
);
80 f
.serial(DefaultPivot
);
87 // ***************************************************************************
88 // ***************************************************************************
90 // ***************************************************************************
91 // ***************************************************************************
94 // ***************************************************************************
95 CBone::CBone(CBoneBase
*boneBase
)
101 IAnimatable::resize(AnimValueLast
);
103 ITransformable::setTransformMode(ITransformable::RotQuat
);
104 ITransformable::setPos( _BoneBase
->DefaultPos
.getDefaultValue() );
105 ITransformable::setRotQuat( _BoneBase
->DefaultRotQuat
.getDefaultValue() );
106 ITransformable::setScale( _BoneBase
->DefaultScale
.getDefaultValue() );
107 ITransformable::setPivot( _BoneBase
->DefaultPivot
.getDefaultValue() );
109 // By default, the bone is not binded to a channelMixer.
111 _RotEulerChannelId
= -1;
112 _RotQuatChannelId
= -1;
116 // No animCtrl by default
119 // Get default BoneBase SkinScale
120 _SkinScale
= _BoneBase
->SkinScale
;
123 // ***************************************************************************
124 ITrack
* CBone::getDefaultTrack (uint valueId
)
131 case PosValue
: return &_BoneBase
->DefaultPos
;
132 case RotEulerValue
: return &_BoneBase
->DefaultRotEuler
;
133 case RotQuatValue
: return &_BoneBase
->DefaultRotQuat
;
134 case ScaleValue
: return &_BoneBase
->DefaultScale
;
135 case PivotValue
: return &_BoneBase
->DefaultPivot
;
138 // No, only ITrnasformable values!
140 // Deriver note: else call BaseClass::getDefaultTrack(valueId);
145 // ***************************************************************************
146 void CBone::registerToChannelMixer(CChannelMixer
*chanMixer
, const std::string
&prefix
)
148 // For CBone, channels are detailled.
149 // Bkup each channelId (for disable).
150 _PosChannelId
= addValue(chanMixer
, PosValue
, OwnerBit
, prefix
, true);
151 _RotEulerChannelId
= addValue(chanMixer
, RotEulerValue
, OwnerBit
, prefix
, true);
152 _RotQuatChannelId
= addValue(chanMixer
, RotQuatValue
, OwnerBit
, prefix
, true);
153 _ScaleChannelId
= addValue(chanMixer
, ScaleValue
, OwnerBit
, prefix
, true);
154 _PivotChannelId
= addValue(chanMixer
, PivotValue
, OwnerBit
, prefix
, true);
156 // Deriver note: if necessary, call BaseClass::registerToChannelMixer(chanMixer, prefix);
159 // ***************************************************************************
160 void CBone::compute(CBone
*parent
, const CMatrix
&rootMatrix
, CSkeletonModel
*skeletonForAnimCtrl
)
162 // compute is called typically 800 time per frame.
167 // get/compute our local matrix
168 const CMatrix
&localMatrix
= getMatrix();
170 // Compute LocalSkeletonMatrix.
174 _LocalSkeletonMatrix
= localMatrix
;
176 // Else, son case, take world matrix from parent.
179 // UnheritScale case.
180 if(_BoneBase
->UnheritScale
)
182 CMatrix invScaleComp
;
187 the scale is rarely ==1, so don't optimize case where it may be.
190 // retrieve our translation
191 localMatrix
.getPos(trans
);
192 // retrieve scale from our father.
193 parent
->getScale(fatherScale
);
194 // inverse this scale.
195 fatherScale
.x
= 1.0f
/ fatherScale
.x
;
196 fatherScale
.y
= 1.0f
/ fatherScale
.y
;
197 fatherScale
.z
= 1.0f
/ fatherScale
.z
;
199 // Compute InverseScale compensation:
200 // with UnheritScale, formula per bone should be T*Sf-1*P*R*S*P-1.
201 // But getMatrix() return T*P*R*S*P-1.
202 // So we must compute T*Sf-1*T-1, in order to get wanted result.
203 invScaleComp
.setScale(fatherScale
);
204 // Faster compute of the translation part: just "trans + fatherScale MUL -trans" where MUL is comp mul
205 trans
.x
-= fatherScale
.x
* trans
.x
;
206 trans
.y
-= fatherScale
.y
* trans
.y
;
207 trans
.z
-= fatherScale
.z
* trans
.z
;
208 invScaleComp
.setPos(trans
);
211 // And finally, we got ParentWM * T*Sf-1*P*R*S*P-1.
212 // Do: _LocalSkeletonMatrix= parent->_LocalSkeletonMatrix * invScaleComp * localMatrix
214 tmp
.setMulMatrixNoProj( parent
->_LocalSkeletonMatrix
, invScaleComp
);
215 _LocalSkeletonMatrix
.setMulMatrixNoProj( tmp
, localMatrix
);
220 // Do: _LocalSkeletonMatrix= parent->_LocalSkeletonMatrix * localMatrix
221 _LocalSkeletonMatrix
.setMulMatrixNoProj( parent
->_LocalSkeletonMatrix
, localMatrix
);
225 // Compute WorldMatrix. Do: _WorldMatrix= rootMatrix * _LocalSkeletonMatrix
226 _WorldMatrix
.setMulMatrixNoProj( rootMatrix
, _LocalSkeletonMatrix
);
228 // Compute BoneSkinMatrix. Easier of no SkinScale
229 if(_SkinScale
==UnitScale
)
231 // Do: _BoneSkinMatrix= _LocalSkeletonMatrix * _BoneBase->InvBindPos
232 _BoneSkinMatrix
.setMulMatrixNoProj( _LocalSkeletonMatrix
, _BoneBase
->InvBindPos
);
236 // Do: _BoneSkinMatrix= _LocalSkeletonMatrix * SkinScale * _BoneBase->InvBindPos
239 scaleMat
.setScale(_SkinScale
);
240 tmp
.setMulMatrixNoProj(_LocalSkeletonMatrix
, scaleMat
);
241 _BoneSkinMatrix
.setMulMatrixNoProj( tmp
, _BoneBase
->InvBindPos
);
244 // When compute is done, do extra user ctrl?
245 if(_AnimCtrl
&& skeletonForAnimCtrl
)
246 _AnimCtrl
->execute(skeletonForAnimCtrl
, this);
250 // ***************************************************************************
251 void CBone::interpolateBoneSkinMatrix(const CMatrix
&otherMatrix
, float interp
)
253 CMatrix
&curMatrix
= _BoneSkinMatrix
;
255 // interpolate rot/scale. Just interpolate basis vectors
256 CVector fatherI
= otherMatrix
.getI();
257 CVector curI
= curMatrix
.getI();
258 curI
= fatherI
*(1-interp
) + curI
*interp
;
259 CVector fatherJ
= otherMatrix
.getJ();
260 CVector curJ
= curMatrix
.getJ();
261 curJ
= fatherJ
*(1-interp
) + curJ
*interp
;
262 CVector fatherK
= otherMatrix
.getK();
263 CVector curK
= curMatrix
.getK();
264 curK
= fatherK
*(1-interp
) + curK
*interp
;
266 curMatrix
.setRot(curI
, curJ
, curK
);
269 CVector fatherPos
= otherMatrix
.getPos();
270 CVector curPos
= curMatrix
.getPos();
271 curPos
= fatherPos
*(1-interp
) + curPos
*interp
;
272 curMatrix
.setPos(curPos
);
276 // ***************************************************************************
277 void CBone::lodEnableChannels(CChannelMixer
*chanMixer
, bool enable
)
281 // Lod Enable channels if they are correclty registered to the channelMixer.
282 if( _PosChannelId
>=0 )
283 chanMixer
->lodEnableChannel(_PosChannelId
, enable
);
284 if( _RotEulerChannelId
>=0 )
285 chanMixer
->lodEnableChannel(_RotEulerChannelId
, enable
);
286 if( _RotQuatChannelId
>=0 )
287 chanMixer
->lodEnableChannel(_RotQuatChannelId
, enable
);
288 if( _ScaleChannelId
>=0 )
289 chanMixer
->lodEnableChannel(_ScaleChannelId
, enable
);
290 if( _PivotChannelId
>=0 )
291 chanMixer
->lodEnableChannel(_PivotChannelId
, enable
);
295 // ***************************************************************************
296 void CBone::setSkinScale(CVector
&skinScale
)
298 _SkinScale
= skinScale
;