GPUSkinCache 사용시, 스켈레탈 메시 컴포넌트 등록 이후 첫프레임의 모프타겟이 적용되지 않습니다.

시퀀스를 통해 스폰한 스켈레탈메시 액터가 스폰 직후 Facial 표현을 위한 모프 타겟을 갖고 있는데, 이것이 적용되지 않아 확인 중에 있습니다.

r.SkinCache.Mode 를 0으로 설정하면 이 문제가 해결되어, 관련 코드를 살펴보던 중 의심 가는 내용이 있어 문의드립니다.

재현에 필요한 프로젝트를 구성하기위해서는 모프 타겟이 포함된 애셋등을 포함하여야 하는데, 이것이 여의치 않아 코드흐름으로만 문의드리는 점 양해부탁드립니다.

먼저 저희 프로젝트는 나나이트를 사용하지 않아, SkeletalRenderGPUSkin에서 발생하는 문제입니다.​

이해하기로는 다음의 순서로 ​GPU 스키닝을 수행하는 것 같습니다.

ProcessStage_MeshDeformer-> ProcessStage_SkinCache -> ProcessStage_Inline-> ProcessStage_Upload

이번 프레임 모프 사용 여부의 결정은 ​SkinCache 스테이지의 SetupSection() 함수 내부에서 MorphVertexBuffer->SectionIds.Contains(SectionIndex) 를 통해 수행하는 것 같습니다.

그런데 MorphVertexBuffer->SectionIds는 Upload Stage의 ​MeshObject->UpdateBufferData() -> UpdateMorphVertexBuffer() 시점에 가서야 채워지는 것 같습니다.

이 때문에 첫 프레임에서 모프를 갱신하지 못하는​ 것으로 파악하고있습니다.

그래서 다음과 같은 방식으로 MorphVertexBuffer의 최초 업데이트가 호출되기 전이면, SectionIDs를 먼저 한번 채워주도록 수정을 시도하였습니다.

결과는 의도한 대로 동작하였는데요.​

void FSkeletalMeshObjectGPUSkin::ProcessUpdatedDynamicData(FRHICommandList& RHICmdList, FGPUSkinCache* GPUSkinCache, EGPUSkinCacheEntryMode Mode)
{
    // 앞부분 생략

    if (Mode == EGPUSkinCacheEntryMode::Raster)
    {
       // RayTracing-specific LOD's can't have a separate morph target buffer at the moment because there is only one morph vertex buffer across the entire mesh.
       if (GEnableMorphTargets && LODData.GetNumVertices() > 0 && (bHasWeightedActiveMorphs || bHasExternalMorphs))
       {
          bMorphNeedsUpdate |= GForceUpdateMorphTargets != 0;

          if (bMorphNeedsUpdate)
          {
             LOD.MorphVertexBufferPool->SetCurrentRevisionNumber(CurrentRevisionNumber);
          }

          MorphVertexBuffer = &LOD.MorphVertexBufferPool->GetMorphVertexBufferForWriting();

          // Force an update if this is the first use of the buffer
          if (!MorphVertexBuffer->bHasBeenUpdated)
          {
             bMorphNeedsUpdate = true;
#if WITH_CUSTOM
             // SkinCache가 SetupSection을 수행할 때(이 함수 뒷부분) bMorph 판단을 위해
             // SectionIds가 필요한데, 원래는 다음 단계(Upload)에서 채워집니다.
             // 이를 방지하기 위해 여기서 미리 DynamicData의 SectionIds를 복사해둡니다.
             MorphVertexBuffer->SectionIds = DynamicData->SectionIdsUseByActiveMorphTargets;
#endif // WITH_CUSTOM
          }

          if (bMorphNeedsUpdate)
          {
             LOD.MorphVertexBufferPool->SetUpdatedFrameNumber(BoneTransformFrameNumber);
          }
       }
       else
       {
          MorphVertexBuffer = nullptr;
          bMorphNeedsUpdate = false;
       }
    }

    // 뒷부분 생략
}

이러한 수정이 적절할까요? 아니면 다른방식으로 수정해야할까요?

의견 부탁드립니다. 감사합니다.​

재현 방법
시퀀스 0프레임에 모프타겟을 갖고있는 스켈레탈 메시 액터를 -1프레임에선 디스폰, 0프레임에서 스폰하도록 하고 0프레임부터 모프타겟이 평가될 수 있도록 합니다.

-1프레임과 0프레임을 오갈 때 재현됩니다.

안녕하세요. 답변이 늦어 죄송합니다.

Level Sequence에서 모프 타겟이 있는 메시에서 첫 프레임에 모프 타겟이 적용되지 않은 모습과 관련된 모습이 확인되는데, 말씀주신 대로 SkeletalMeshUpdater 기준으로 ProcessStage_SkinCache 이후 Upload 단계에서 MorphVertexBuffer->SectionIds가 채워지는 흐름이 확인되고, 스폰 직후 첫 프레임에 SkinCache의 SetupSection() 시점에 SectionIds가 비어 있어, 모프 적용 여부 판단이 늦어질 가능성이 있어 보입니다.

해당 내용은 담당 팀에 전달한 후 진행 상황을 공유 드릴 수 있도록 하겠습니다.

그리고 재현 조건에서 모프 타겟 값은 어떤 방식으로 적용하고 계신지(예: 시퀀스 커브/모프 트랙, 애니메이션 커브, Control Rig, Event 트랙에서 SetMorphTarget() 호출 등)와 함께 참고할 만한 설정이나 추가 상황도 공유해주신다면 참고하겠습니다.

감사합니다.

안녕하세요.

시퀀스 커브를 통해 모프 값들을 설정하고 무비 틱 단계에서 해당 CustomSkeletalMeshComponent의 배열에 모프/웨이트 맵에 기록해둡니다.

CustomSkeletalMeshComponent::Tick(TG_Prephysics)에서 기타 Tick에 의해 호출해야하는 모프들(눈깜빡임 등)을 반영한 후 SetMorphTarget()을 호출하여 모프타겟 값을 적용하고 있습니다.

액터가 Spawn된 시점의 프레임카운터와 동일한 프레임에 생성하는 렌더프록시에 모프가 잘 전달되는 점은 확인했습니다.

안녕하세요.

해당 내용을 리포트 하여 티켓 UE-356717(링크) 이 생성되었습니다. 해당 링크에서 진행상황을 확인 하실 수 있습니다.

추가로 알려주신 내용도 확인하여 전달 할 수 있도록 하겠습니다.