Как программно переместить кости загруженного ресурса в Away3D?

Я загружаю 3D-актив в сцену Away3D, и я хотел бы изменить положение костей в коде.

Загрузка активов все идет хорошо, я беру указатель на Mesh а также Skeleton при загрузке:

private function onAssetComplete(evt:AssetEvent):void
{
    if(evt.asset.assetType == AssetType.SKELETON){
        _skeleton = evt.asset as Skeleton;
    } else if (evt.asset.assetType == AssetType.MESH) {
        _mesh = evt.asset as Mesh;
    }
}

После того, как актив (ы) завершил загрузку, у меня есть действительный Skeleton а также Mesh Например, модель также видна в моей сцене. Следующее, что я попробовал, это следующее.

// create a matrix with the desired joint (bone) position
var pos:Matrix3D = new Matrix3D();
pos.position = new Vector3D(60, 0, 0);
pos.invert();

// get the joint I'd like to modifiy. The bone is named "left"
var joint:SkeletonJoint = _skeleton.jointFromName("left");

// assign joint position
joint.inverseBindPose = pos.rawData;

Этот код выполняется без ошибок, но новая позиция не применяется к видимой геометрии, например. положение кости не меняется вообще.

Есть ли дополнительный шаг, который я здесь пропускаю? Должен ли я переназначить скелет Mesh каким-то образом? Или я должен явно сказать мешу, что положение костей изменилось?

1 ответ

Решение

Возможно, это не лучший способ решить эту проблему, но вот что я понял:

Away3D применяет совместные преобразования к геометрии только при наличии анимации. Чтобы применить ваши преобразования, ваша геометрия должна иметь анимацию, или вам придется создавать анимацию в коде. Вот как вы это делаете (желательно в вашем LoaderEvent.RESOURCE_COMPLETE метод обработчика:

// create a new pose for the skeleton
var rootPose:SkeletonPose = new SkeletonPose();

// add all the joints to the pose
// the _skeleton member is being assigned during the loading phase where you
// look for AssetType.SKELETON inside a AssetEvent.ASSET_COMPLETE listener
for each(var joint:SkeletonJoint in _skeleton.joints){
    var m:Matrix3D = new Matrix3D(joint.inverseBindPose);
    m.invert();
    var p:JointPose = new JointPose();
    p.translation = m.transformVector(p.translation);
    p.orientation.fromMatrix(m);
    rootPose.jointPoses.push(p);
}

// create idle animation clip by adding the root pose twice
var clip:SkeletonClipNode = new SkeletonClipNode();
clip.addFrame(rootPose, 1000);
clip.addFrame(rootPose, 1000);
clip.name = "idle";

// build animation set
var animSet:SkeletonAnimationSet = new SkeletonAnimationSet(3);
animSet.addAnimation(clip);

// setup animator with set and skeleton
var animator:SkeletonAnimator = new SkeletonAnimator(animSet, _skeleton);

// assign the newly created animator to your Mesh.
// This example assumes that you grabbed the pointer to _myMesh during the 
// asset loading stage (by looking for AssetType.MESH)
_myMesh.animator = animator;

// run the animation
animator.play("idle");

// it's best to keep a member that points to your pose for
// further modification
_myPose = rootPose;

После этого шага инициализации вы можете динамически изменять свои совместные позы (вы меняете положение, изменяя translation свойство и вращение, изменяя orientation имущество). Пример:

_myPose.jointPoses[2].translation.x = 100;

Если вы не знаете индексы ваших суставов и скорее адресуете кости по имени, это должно сработать:

var jointIndex:int = _skeleton.jointIndexFromName("myBoneName");
_myPose.jointPoses[jointIndex].translation.y = 10;

Если вы часто используете поиск по названию (скажем, каждый кадр), и в вашей модели много костей, рекомендуется создать Dictionary где вы можете искать индексы костей по имени. Причина этого заключается в том, что реализация jointIndexFromName выполняет линейный поиск по всем соединениям, что бесполезно, если вы делаете это несколько раз.

Другие вопросы по тегам