Как создать модульный Pawn

Как создать модульный Pawn


Многие современные игры позволяют игроку кастомизировать персонажа, за которого они играют. В то время, как атачменты через сокеты или кости работают отлично для не анимированных или отдельных анимированых эффектов. Они не работают достаточно хорошо, когда вы хотите перемещаться персонажем как целой единицей.
К примеру, представьте себе, если вы хотите дать возможность игроку создавать персонажа с разными рубашками и штанами. Так как эти части были совмещены вместе и представляют собой персонажа, было бы очень не реалистично, если анимации были бы не синхронизированы.

В этом примере, мы видим Lauryn с разными наплечниками, разными сапогами и разными кистями. Тени и анимации работают автоматически с едва заметным рывком.




Методы


Имеется два метода, чтобы достичь этого.



- Несколько Skeletal Mesh Component'ов через эктор - Этот метод является самым гибким, поскольку он позволяет ускорить время изменений в скелетал меше. Однако, это может повлиять на производительность с каждого скелетал меша загруженного на уровне.
- Композитинг меша (только для Лицензиатов)- Этот метод составляет меш, генерируя один меш из нескольких. Этот метод не будет описан здесь.

Скриптим модулярный Pawn


Это класс модулярного Pawn'a, который определяет Skeletal Mesh Component. Каждый Skeletal Mesh Component представляется частью Pawn'a, который может быть заменен другой частью. Только один компонент может быть родительским, в данном случае этот компонент голова.

Родительский компонент отвечает за расчет данных скелетной анимации, которая используется всеми дочерними компонентами этого скелетал меша. Все дочерние компоненты также получают все данные о перемещении, вращении и масштабировании ихнего родителя.

Для лучших результатов, убедитесь, что все скелетал меши используют одинаковый скелет и сделаны для одинаковых анимаций. Все вершины должны быть подогнаны напрямую к скелету, так как нет никакой необходимости центрировать каждый скелетал меш перед экспортом.

________________________ModularPawn.uc___________________________


class ModularPawn extends UTPawn
  Placeable;

// Skeletal mesh which represents the head. Parent skeletal mesh component.
var(ModularPawn) const SkeletalMeshComponent HeadSkeletalMesh;
// Skeletal mesh which represents the torso. Child to the head skeletal mesh component.
var(ModularPawn) const SkeletalMeshComponent TorsoSkeletalMesh;
// Skeletal mesh which represents the arms. Child to the head skeletal mesh component.
var(ModularPawn) const SkeletalMeshComponent ArmsSkeletalMesh;
// Skeletal mesh which represents the thighs. Child to the head skeletal mesh component.
var(ModularPawn) const SkeletalMeshComponent ThighsSkeletalMesh;
// Skeletal mesh which represents the boots. Child to the head skeletal mesh component.
var(ModularPawn) const SkeletalMeshComponent BootsSkeletalMesh;
// Skeletal mesh which represents the left shoulder pad. Child to the head skeletal mesh component.
var(ModularPawn) const SkeletalMeshComponent LeftShoulderPadSkeletalMesh;
// Skeletal mesh which represents the right shoulder pad. Child to the head skeletal mesh component.
var(ModularPawn) const SkeletalMeshComponent RightShoulderPadSkeletalMesh;

defaultproperties
{
  // Remove UTPawn's defined skeletal mesh
  Components.Remove(WPawnSkeletalMeshComponent)

  // Create the animation sequence
  Begin Object class=AnimNodeSequence Name=AnimNodeSequence
  End Object

  // Create the head skeletal mesh component
  Begin Object Class=SkeletalMeshComponent Name=HeadSkeletalMeshComponent      
    bCacheAnimSequenceNodes=false
    AlwaysLoadOnClient=true
    AlwaysLoadOnServer=true
    bOwnerNoSee=true
    CastShadow=true
    BlockRigidBody=true
    bUpdateSkelWhenNotRendered=false
    bIgnoreControllersWhenNotRendered=true
    bUpdateKinematicBonesFromAnimation=true
    bCastDynamicShadow=true
    RBChannel=RBCC_Untitled3
    RBCollideWithChannels=(Untitled3=true)
    LightEnvironment=MyLightEnvironment
    bOverrideAttachmentOwnerVisibility=true
    bAcceptsDynamicDecals=false
    AnimTreeTemplate=AnimTree'CH_AnimHuman_Tree.AT_CH_Human'
    bHasPhysicsAssetInstance=true
    TickGroup=TG_PreAsyncWork
    MinDistFactorForKinematicUpdate=0.2
    bChartDistanceFactor=true
    RBDominanceGroup=20
    MotionBlurScale=0.0
    bUseOnePassLightingOnTranslucency=true
    bPerBoneMotionBlur=true
    // Set the animation node sequence so we can test the animation
    Animations=AnimNodeSequence
  End Object
  HeadSkeletalMesh=HeadSkeletalMeshComponent
  Components.Add(HeadSkeletalMeshComponent)

  // Create the torso skeletal mesh component
  Begin Object Class=SkeletalMeshComponent Name=TorsoSkeletalMeshComponent
    bCacheAnimSequenceNodes=false
    AlwaysLoadOnClient=true
    AlwaysLoadOnServer=true
    bOwnerNoSee=true
    CastShadow=true
    BlockRigidBody=true
    bUpdateSkelWhenNotRendered=false
    bIgnoreControllersWhenNotRendered=true
    bUpdateKinematicBonesFromAnimation=true
    bCastDynamicShadow=true
    RBChannel=RBCC_Untitled3
    RBCollideWithChannels=(Untitled3=true)
    LightEnvironment=MyLightEnvironment
    bOverrideAttachmentOwnerVisibility=true
    bAcceptsDynamicDecals=false
    bHasPhysicsAssetInstance=true
    TickGroup=TG_PreAsyncWork
    MinDistFactorForKinematicUpdate=0.2
    bChartDistanceFactor=true
    RBDominanceGroup=20
    MotionBlurScale=0.0
    bUseOnePassLightingOnTranslucency=true
    bPerBoneMotionBlur=true
    // Assign the parent animation component to the head skeletal mesh component. This ensures that
    // the pawn animates as if it was one skeletal mesh component.
    ParentAnimComponent=HeadSkeletalMeshComponent
    // Assign the shadow parent component to the head skeletal mesh component. This is used to speed up
    // the rendering of the shadow for this pawn and to prevent shadow overlaps from occur.
    ShadowParent=HeadSkeletalMeshComponent
  End Object
  TorsoSkeletalMesh=TorsoSkeletalMeshComponent
  Components.Add(TorsoSkeletalMeshComponent)

  // Create the arms skeletal mesh component
  Begin Object Class=SkeletalMeshComponent Name=ArmsSkeletalMeshComponent
    bCacheAnimSequenceNodes=false
    AlwaysLoadOnClient=true
    AlwaysLoadOnServer=true
    bOwnerNoSee=true
    CastShadow=true
    BlockRigidBody=true
    bUpdateSkelWhenNotRendered=false
    bIgnoreControllersWhenNotRendered=true
    bUpdateKinematicBonesFromAnimation=true
    bCastDynamicShadow=true
    RBChannel=RBCC_Untitled3
    RBCollideWithChannels=(Untitled3=true)
    LightEnvironment=MyLightEnvironment
    bOverrideAttachmentOwnerVisibility=true
    bAcceptsDynamicDecals=false
    bHasPhysicsAssetInstance=true
    TickGroup=TG_PreAsyncWork
    MinDistFactorForKinematicUpdate=0.2
    bChartDistanceFactor=true
    RBDominanceGroup=20
    MotionBlurScale=0.0
    bUseOnePassLightingOnTranslucency=true
    bPerBoneMotionBlur=true
    // Assign the parent animation component to the head skeletal mesh component. This ensures that
    // the pawn animates as if it was one skeletal mesh component.
    ParentAnimComponent=HeadSkeletalMeshComponent
    // Assign the shadow parent component to the head skeletal mesh component. This is used to speed up
    // the rendering of the shadow for this pawn and to prevent shadow overlaps from occur.
    ShadowParent=HeadSkeletalMeshComponent
  End Object
  ArmsSkeletalMesh=ArmsSkeletalMeshComponent
  Components.Add(ArmsSkeletalMeshComponent)

  // Create the thighs skeletal mesh component
  Begin Object Class=SkeletalMeshComponent Name=ThighsSkeletalMeshComponent
    bCacheAnimSequenceNodes=false
    AlwaysLoadOnClient=true
    AlwaysLoadOnServer=true
    bOwnerNoSee=true
    CastShadow=true
    BlockRigidBody=true
    bUpdateSkelWhenNotRendered=false
    bIgnoreControllersWhenNotRendered=true
    bUpdateKinematicBonesFromAnimation=true
    bCastDynamicShadow=true
    RBChannel=RBCC_Untitled3
    RBCollideWithChannels=(Untitled3=true)
    LightEnvironment=MyLightEnvironment
    bOverrideAttachmentOwnerVisibility=true
    bAcceptsDynamicDecals=false
    bHasPhysicsAssetInstance=true
    TickGroup=TG_PreAsyncWork
    MinDistFactorForKinematicUpdate=0.2
    bChartDistanceFactor=true
    RBDominanceGroup=20
    MotionBlurScale=0.0
    bUseOnePassLightingOnTranslucency=true
    bPerBoneMotionBlur=true
    // Assign the parent animation component to the head skeletal mesh component. This ensures that
    // the pawn animates as if it was one skeletal mesh component.
    ParentAnimComponent=HeadSkeletalMeshComponent
    // Assign the shadow parent component to the head skeletal mesh component. This is used to speed up
    // the rendering of the shadow for this pawn and to prevent shadow overlaps from occur.
    ShadowParent=HeadSkeletalMeshComponent
  End Object
  ThighsSkeletalMesh=ThighsSkeletalMeshComponent
  Components.Add(ThighsSkeletalMeshComponent)

  // Create the boots skeletal mesh component
  Begin Object Class=SkeletalMeshComponent Name=BootsSkeletalMeshComponent
    bCacheAnimSequenceNodes=false
    AlwaysLoadOnClient=true
    AlwaysLoadOnServer=true
    bOwnerNoSee=true
    CastShadow=true
    BlockRigidBody=true
    bUpdateSkelWhenNotRendered=false
    bIgnoreControllersWhenNotRendered=true
    bUpdateKinematicBonesFromAnimation=true
    bCastDynamicShadow=true
    RBChannel=RBCC_Untitled3
    RBCollideWithChannels=(Untitled3=true)
    LightEnvironment=MyLightEnvironment
    bOverrideAttachmentOwnerVisibility=true
    bAcceptsDynamicDecals=false
    bHasPhysicsAssetInstance=true
    TickGroup=TG_PreAsyncWork
    MinDistFactorForKinematicUpdate=0.2
    bChartDistanceFactor=true
    RBDominanceGroup=20
    MotionBlurScale=0.0
    bUseOnePassLightingOnTranslucency=true
    bPerBoneMotionBlur=true
    // Assign the parent animation component to the head skeletal mesh component. This ensures that
    // the pawn animates as if it was one skeletal mesh component.
    ParentAnimComponent=HeadSkeletalMeshComponent
    // Assign the shadow parent component to the head skeletal mesh component. This is used to speed up
    // the rendering of the shadow for this pawn and to prevent shadow overlaps from occur.
    ShadowParent=HeadSkeletalMeshComponent
  End Object
  BootsSkeletalMesh=BootsSkeletalMeshComponent
  Components.Add(BootsSkeletalMeshComponent)

  // Create the left shoulder pad skeletal mesh component
  Begin Object Class=SkeletalMeshComponent Name=LeftShouldPadSkeletalMeshComponent
    bCacheAnimSequenceNodes=false
    AlwaysLoadOnClient=true
    AlwaysLoadOnServer=true
    bOwnerNoSee=true
    CastShadow=true
    BlockRigidBody=true
    bUpdateSkelWhenNotRendered=false
    bIgnoreControllersWhenNotRendered=true
    bUpdateKinematicBonesFromAnimation=true
    bCastDynamicShadow=true
    RBChannel=RBCC_Untitled3
    RBCollideWithChannels=(Untitled3=true)
    LightEnvironment=MyLightEnvironment
    bOverrideAttachmentOwnerVisibility=true
    bAcceptsDynamicDecals=false
    bHasPhysicsAssetInstance=true
    TickGroup=TG_PreAsyncWork
    MinDistFactorForKinematicUpdate=0.2
    bChartDistanceFactor=true
    RBDominanceGroup=20
    MotionBlurScale=0.0
    bUseOnePassLightingOnTranslucency=true
    bPerBoneMotionBlur=true
    // Assign the parent animation component to the head skeletal mesh component. This ensures that
    // the pawn animates as if it was one skeletal mesh component.
    ParentAnimComponent=HeadSkeletalMeshComponent
    // Assign the shadow parent component to the head skeletal mesh component. This is used to speed up
    // the rendering of the shadow for this pawn and to prevent shadow overlaps from occur.
    ShadowParent=HeadSkeletalMeshComponent
  End Object
  LeftShoulderPadSkeletalMesh=LeftShouldPadSkeletalMeshComponent
  Components.Add(LeftShouldPadSkeletalMeshComponent)

  // Create the right shoulder pad skeletal mesh component
  Begin Object Class=SkeletalMeshComponent Name=RightShoulderPadSkeletalMeshComponent
    bCacheAnimSequenceNodes=false
    AlwaysLoadOnClient=true
    AlwaysLoadOnServer=true
    bOwnerNoSee=true
    CastShadow=true
    BlockRigidBody=true
    bUpdateSkelWhenNotRendered=false
    bIgnoreControllersWhenNotRendered=true
    bUpdateKinematicBonesFromAnimation=true
    bCastDynamicShadow=true
    RBChannel=RBCC_Untitled3
    RBCollideWithChannels=(Untitled3=true)
    LightEnvironment=MyLightEnvironment
    bOverrideAttachmentOwnerVisibility=true
    bAcceptsDynamicDecals=false
    bHasPhysicsAssetInstance=true
    TickGroup=TG_PreAsyncWork
    MinDistFactorForKinematicUpdate=0.2
    bChartDistanceFactor=true
    RBDominanceGroup=20
    MotionBlurScale=0.0
    bUseOnePassLightingOnTranslucency=true
    bPerBoneMotionBlur=true
    // Assign the parent animation component to the head skeletal mesh component. This ensures that
    // the pawn animates as if it was one skeletal mesh component.
    ParentAnimComponent=HeadSkeletalMeshComponent
    // Assign the shadow parent component to the head skeletal mesh component. This is used to speed up
    // the rendering of the shadow for this pawn and to prevent shadow overlaps from occur.
    ShadowParent=HeadSkeletalMeshComponent
  End Object
  RightShoulderPadSkeletalMesh=RightShoulderPadSkeletalMeshComponent
  Components.Add(RightShoulderPadSkeletalMeshComponent)
}


Примечания


В классе выше, Anim Node Sequence был определен для того, чтобы разрешить вам протестировать анимацию. Это остановит нормальную работу Anim Tree, тем самым удалив Anim Node Sequence из скрипта класса или объекта (внутри архетипа), чтобы Anim Tree заработал снова.

Параметры модульного Pawn'a


После помещения Модульного Pawn'а на уровень, открыв это окно с параметрами можно увидеть все скелетал меши.



Разверните все вкладки каждого скелетал меша и настройте все скелетал меши. Родительский Skeletal Mesh Component должен иметь Anim Tree Template, Physics Asset, AnimSets набор. В данном случае Head Skeletal Mesh все это содержит.





После того как вы настроите каждый скелетал меш, они появятся в редакторе.





Родительский Skeletal Mesh Component (Head Skeletal Mesh) имеет Anim Node Sequence, установленное для Анимаций объекта. Разверните вкладку Animations, чтобы увидеть Anim Node Sequence. Введите имя анимации в поле напротив Anim Seq Name, чтобы движок ее нашел. Это обновит skeletal mesh component'ы внутри редактора. Для визуализации анимаций запустите PIE.





Все перемещения, вращения и масштабирования родительского Skeletal Mesh Component'а (Head Skeletal Mesh) влияют на дочерние Skeletal Mesh Component'ы. Отрегулируйте их, если вы заметили, что Skeletal Mesh Component'ы не вмещаются в Цилиндре Столкновений (Collision Cylinder), или направления Skeletal Mesh Component'ов не верны относительно вращениям пешки, или если Skeletal Mesh Component'ы слишком малы. Вы также можете настроить версии дочерних Skeletal Mesh Component'ов, просто помните, что они должны относится к настройкам родительского Skeletal Mesh Component'а.





Unreal AnimSet Editor


Если вы хотите просмотреть модулярный Pawn без запуска PIE, вы можете это сделать в Unreal AnimSet Editor. Заполнив поля "Extra Mesh #" (выделены красным цветом), вы можете назначить несколько мешей для одинакового скелета и анимаций. В этом примере, большая часть мешей Lauryn's была назначена. Однако, не хватает слота для ботинок.





После того как вы установите экстра меши, кликните по вкладке Anim для отображения списка анимаций. Выделите любую анимацию и проиграйте ее. Вы должны увидеть как все скелетал меши анимированы.





Когда это используют...


Существует еще один способ прикрепления вещей на скелетал меши, а именно с помощью сокетов. Итак, вопрос в том, когда вы будете использовать сокеты и этот метод? Ответ на этот вопрос, когда вам нужна синхронизированная анимация. В данном кокретном случае, все меши  должны быть синхронизированны, так как это Pawn. Наплечники также могут быть закрепленны с помощью сокетов.

Перевел Александр Деменков[link] по оригинальной статье Epic Games. Оригинал [link].

1 комментарий:

Leave the comment [here]