Bug in binding cocos2d armature to other armature bones
In cocos2dx, The rmature skeleton can be bound to another armature. This function is used in my project to complete the ride function, but the following bug is found during use, the close-up is recorded here.
First, let's talk about cocos2dx code. The update function of the cocos2dx skeleton contains the following code for Matrix update of the skeleton.
if (_boneTransformDirty) { if (_dataVersion >= VERSION_COMBINED) { TransformHelp::nodeConcat(*_tweenData, *_boneData); _tweenData->scaleX -= 1; _tweenData->scaleY -= 1; }//(1) _worldInfo->copy(_tweenData); _worldInfo->x = _tweenData->x + _position.x; _worldInfo->y = _tweenData->y + _position.y; _worldInfo->scaleX = _tweenData->scaleX * _scaleX; _worldInfo->scaleY = _tweenData->scaleY * _scaleY; _worldInfo->skewX = _tweenData->skewX + _skewX + CC_DEGREES_TO_RADIANS(_rotationZ_X); _worldInfo->skewY = _tweenData->skewY + _skewY - CC_DEGREES_TO_RADIANS(_rotationZ_Y);//(2) if(_parentBone) { applyParentTransform(_parentBone); } else { if (_armatureParentBone) //(3) { applyParentTransform(_armatureParentBone); } }//(4) TransformHelp::nodeToMatrix(*_worldInfo, _worldTransform);//(5) if (_armatureParentBone) { _worldTransform = TransformConcat(_worldTransform, _armature->getNodeToParentTransform()); } }
In the above Code,
1. The program first calculates the transformation information of bone,
2. in step 2, if the skeleton has a parent bone, multiply it by the transformation information of the parent bone. If there is no parent skeleton but the armature of the skeleton has a parent skeleton (that is, armayure is used as the display of the bone of other armature, then multiply the conversion information of the parent skeleton of armature first.
3. Step 4 converts worldinfo to a matrix.
4. in step 5, the armature transformation information of bone is applied to the transformation matrix to obtain the final matrix information of the skeleton.
The problem lies in the Code marked 3 above. We all know that matrix transformation does not meet the exchange law (except in a few cases, of course ). However, the relationship between the skeleton matrices should be as follows:
ParentArmature ------- armatureParentBone ------------ armature ------------ bone
Or armature -----------.... ------ ParentBone ----- some parentBone is omitted in the bone.
Therefore, if armatureParentBone is not included in the above Code, the matrix transformation relationship is bone * parentBone *... * parentBone. The result is correct, that is, no armature is used as the render of bone.
However, if armature is used as the render of bone, the relationship is bone * armatureParentBone * armature, so there is a problem in the order of matrix transformation. Therefore, I made some modifications to the Code as follows:
//if it is a armature display render node, apply transform to armature. BaseData worldInfo; if (!_parentBone && _armatureParentBone) { //bone * armature TransformHelp::nodeToMatrix(*_worldInfo, _worldTransform); _worldTransform = TransformConcat( _armature->getNodeToParentTransform(), _worldTransform); TransformHelp::matrixToNode(_worldTransform, worldInfo); } else { worldInfo = *_worldInfo; } BaseData cache = *_worldInfo; *_worldInfo = worldInfo; //apply to parent bone. if(_parentBone) //bone * parentbone { applyParentTransform(_parentBone); } else { // * armatureParentBone if (_armatureParentBone) { applyParentTransform(_armatureParentBone); } } TransformHelp::nodeToMatrix(*_worldInfo, _worldTransform);
In the above Code, if bone does not have parentBone and has armatureParentBone, multiply it by the armature matrix.
If not, multiply it by the transformation of parentBone.
If armatureparentBone exists, multiply it by the transformation of parenBone.