【UE4】在 Dedicate Server 上刷新一帧骨骼 Mesh Pose

问题描述

  在 UE4 中,为了性能优化,常会在 Dedicate Server 上把 Mesh 的 Tick 关掉(即 OnlyTickMontagesWhenNotRendered),使其在在服务器上保持 TPose,只在客户端上实时刷新 Mesh Pose(即 AlwaysTickPoseAndRefreshBones)。

if (GetNetMode() == NM_DedicatedServer && GetMesh())
{
	GetMesh()->VisibilityBasedAnimTickOption = EVisibilityBasedAnimTickOption::OnlyTickPoseWhenRendered;
}

  这样会导致一个问题:当需要在服务器上知道 Mesh Pose 的时候(比如计算 Socket 位置的时候),如在服务器上释放一个法球,法球出生 Transform 为法师特定时刻手的 Transform,那就会计算出错(因为服务器上是 TPose)。
  简单的解决方案就是根据 Root 点配置偏移,通过偏移达到从手的位置释放法球的效果,但是这样的实现方式下,无论什么姿势,什么动作,法球 Spawn 位置固定,表现会不好。
  最好的方法还是在服务器是 Spawn 法球之前,Tick 一次 Mesh Pose,也就是从 TPose 变成正确的(和客户端一致)Pose。参考 UE4 AnswerHub,Tick 方法如下:

if (GetMesh())
{
	GetMesh()->TickPose(0.f, false);
	GetMesh()->RefreshBoneTransforms();
}

  从表现上看,确实可以达到计算服务器当前帧的 Pose 的目的,但是也发现了新的问题(TriggerAnimNotifies 递归调用问题):

TriggerAnimNotifies 递归调用问题

  参考 【UE4】TriggerAnimNotifies 递归调用问题,即 在 NotifyBegin 或者 NotifyEnd 的流程中,调用会触发 TriggerAnimNotifies 函数的方法,则会出现这一帧内这个 NotifyState 触发了一次 Begin,两次 End。
  重新看 Tick Pose 的调用:

GetMesh()->TickPose(0.f, false);
GetMesh()->RefreshBoneTransforms();

  TickPose 部分源码:

void USkeletalMeshComponent::TickPose(float DeltaTime, bool bNeedsValidRootMotion)
{
	Super::TickPose(DeltaTime, bNeedsValidRootMotion);

	if (ShouldTickAnimation())
	{
		// ...
		// 计算 DeltaTimeForTick;
		TickAnimation(DeltaTimeForTick, bNeedsValidRootMotion);
		// ...
	}
	// ...
}

  TickAnimation 部分源码:

void USkeletalMeshComponent::TickAnimation(float DeltaTime, bool bNeedsValidRootMotion)
{
	//...

	if (SkeletalMesh != nullptr)
	{
		// We're about to UpdateAnimation, this will potentially queue events that we'll need to dispatch.
		bNeedsQueuedAnimEventsDispatched = true;

		// We update linked instances first incase we're using either root motion or non-threaded update.
		// This ensures that we go through the pre update process and initialize the proxies correctly.
		for (UAnimInstance* LinkedInstance : LinkedInstances)
		{
			// Sub anim instances are always forced to do a parallel update 
			LinkedInstance->UpdateAnimation(DeltaTime * GlobalAnimRateScale, false, UAnimInstance::EUpdateAnimationFlag::ForceParallelUpdate);
		}

		if (AnimScriptInstance != nullptr)
		{
			// Tick the animation
			AnimScriptInstance->UpdateAnimation(DeltaTime * GlobalAnimRateScale, bNeedsValidRootMotion);
		}

		if(ShouldUpdatePostProcessInstance())
		{
			PostProcessAnimInstance->UpdateAnimation(DeltaTime * GlobalAnimRateScale, false);
		}

		/**
			If we're called directly for autonomous proxies, TickComponent is not guaranteed to get called.
			So dispatch all queued events here if we're doing MontageOnly ticking.
		*/
		if (ShouldOnlyTickMontages(DeltaTime))
		{
			ConditionallyDispatchQueuedAnimEvents();
		}
	}
}

  ConditionallyDispatchQueuedAnimEvents 会触发动画通知,所以如果我们不希望触发,DeltaTime 应该传 0,且本身如果希望当前帧,也应该传入 0。
  RefreshBoneTransforms 部分源码:

void USkeletalMeshComponent::RefreshBoneTransforms(FActorComponentTickFunction* TickFunction)
{
	// ...
	
	if (TickFunction == nullptr && ShouldBlendPhysicsBones())
	{
		FinalizeBoneTransform();
	}
}

  FinalizeBoneTransform 会调用 ConditionallyDispatchQueuedAnimEvents()(会判断 bNeedsQueuedAnimEventsDispatched,这个变量在 TickAnimation 里被设为 true),最终调用 TriggerAnimNotifies,造成还没有 MoveTemp,就又触发了一次 End,即一次 Begin,两次 End。

解决方案

  为了避免这个问题,可以如下调用,也可达到刷新一帧 Mesh Pose 的效果:

if (SkelMeshComponent->AnimScriptInstance)
{
	// Tick the animation
	SkelMeshComponent->AnimScriptInstance->UpdateAnimation(0.f, false);
}
SkelMeshComponent->RefreshBoneTransforms();

  不过 UE 自身源码中也存在如下代码(不确定是没有考虑这个问题,还是觉得两次 End 没有什么问题):

void USkeletalMeshComponent::InitAnim(bool bForceReinit)
{
	// ...
	
	//...
	{
		TickAnimation(0.f, false);
		RefreshBoneTransforms();
	}
	
	// ...
}

相关参考

  1. 【UE4】TriggerAnimNotifies 递归调用问题
  2. Dedicated server tick mesh pose for a single frame
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: My Approach to Difficulties in Learning Learning is not always easy, and we all face difficulties and challenges at some point in our educational journey. When faced with difficulties, it is important to have a strategy for overcoming them. Here are a few approaches that I have found to be effective in tackling learning challenges. One of the most important things to do when faced with a difficult concept is to break it down into smaller, more manageable pieces. This can be done by identifying the key takeaways from the material and focusing on understanding those key points. Another useful approach is to seek help from others. Whether it be talking to a classmate, teacher or tutor, getting a different perspective on a difficult topic can be very beneficial. They can also offer guidance and advice on how to approach the material and provide resources to help with understanding. Practice is also a key aspect of overcoming learning difficulties. By practicing a concept or skill, it will become more familiar and easier to understand. For example, working on practice problems or doing sample questions can help in math or science classes, while using flashcards or repetition can help with memorization. Finally, it's important to be patient with yourself and not give up too easily. Learning is a process and it may take time to fully understand a concept. It's also important to remember that making mistakes is a natural part of the learning process. In summary, my approach to difficulties in learning involves breaking down the material into manageable pieces, seeking help from others, practicing regularly, and being patient and persistent. ### 回答2: My Approach to Difficulties in Learning When faced with difficulties in learning, I adopt a series of strategies to overcome them. Firstly, I break down the problem or concept into smaller, manageable parts. By doing so, I am able to focus on each component individually, gaining a clearer understanding of the whole picture. Secondly, I actively seek help and guidance. Whether it is from my teachers, classmates, or online resources, I am not hesitant to reach out and ask for assistance. Collaborating with others not only enhances my knowledge, but also allows me to learn from their perspectives and experiences. Additionally, I maintain a positive mindset, reminding myself that mistakes are an integral part of the learning process. Rather than becoming discouraged by setbacks, I view them as opportunities for growth and improvement. By embracing challenges, I become more resilient and develop a sense of perseverance. Moreover, I create a structured study routine to effectively manage my time and resources. I prioritize tasks and allocate sufficient time for each subject, ensuring that I dedicate quality attention to all aspects of my learning. This not only helps me stay organized but also prevents procrastination. Lastly, I regularly review and revise the material learnt. Repetition is key to solidifying knowledge and retaining information. By regularly revisiting past lessons, I reinforce my understanding and reinforce the concepts, improving long-term retention. In conclusion, my approach to difficulties in learning involves breaking down problems, seeking help, maintaining a positive mindset, creating a structured study routine, and reviewing regularly. By employing these strategies, I am able to effectively navigate obstacles and enhance my learning experience. ### 回答3: 我的应对困难的方法 Learning is a journey filled with ups and downs. Throughout my academic journey, I have encountered various difficulties that have challenged me and pushed me to find effective ways to overcome them. Here are some of my approaches to dealing with difficulties in learning. Firstly, when faced with a difficult concept or subject, I believe it is essential to seek help. I usually start by reaching out to my teachers or professors for guidance. They have the expertise and knowledge to explain complex ideas in a simplified manner. Additionally, I also consult my classmates who might have a better understanding of the topic. Collaborating with others not only enhances my learning experience but also provides alternative perspectives that help broaden my understanding. Furthermore, time management plays a crucial role in overcoming learning obstacles. I have learned to prioritize tasks and allocate my study time effectively. By setting realistic goals and breaking down larger tasks into smaller manageable chunks, I can stay organized and avoid feeling overwhelmed. This approach allows me to focus on one task at a time, increasing productivity and comprehension. Another strategy I employ is utilizing various resources available to me. Technology has proven to be a valuable tool in my learning process. I take advantage of online platforms, educational apps, and websites that offer tutorials and explanations. These resources provide additional support and allow me to review and reinforce my understanding of challenging concepts at my own pace. Lastly, a positive mindset is crucial when facing difficulties in learning. Instead of viewing challenges as setbacks, I perceive them as opportunities for growth. I remind myself that mistakes and failures are part of the learning process. By embracing a growth mindset, I become more resilient and motivated to push through and find solutions to my difficulties. All in all, my approach to difficulties in learning involves seeking help, effective time management, utilizing various resources, and maintaining a positive mindset. By implementing these strategies, I have been able to overcome obstacles and continue progressing in my academic journey.
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值