Как создать модульный 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].
Кому помогло или просто есть вопросы пишите.
ОтветитьУдалить