2

Greetings to everyone,

Greetings to everyone. : )

I'm implementing a VR experience on UE4 that detects the movement of the VR experience user, and then updates the corresponding pose of the avatar or representation of the user inside the virtual world.

For doing so, I've implemented this behavior with C++ based on what is said on this topic:

https://forums.unrealengine.com/showthread.php?25264-Pose-a-skeletal-mesh-in-runtime

That is, I have an USkeletalMeshComponent (whose Skeletal mesh is the one seen on screen), and an UPoseableMeshComponent (being set as the "master pose component" for the USkeletalMeshComponent), that receives the rotation data as quaternions from each tracking sensor.

One hand, the mesh for the UPoseableMeshComponent will be set to the mesh of the USkeletalMeshComponet. The other hand, the bones of the poseable mesh are updated with the corresponding rotation data coming from the tracking sensors for each bone, which makes automatically the skeletal mesh to be updated accordingly due to the UPoseableMeshComponent was set as "master pose component" for the USkeletalMeshComponent.

This works pefectly when working with all the body parts that are not finger phalanxes, because rotations are set on those body parts in world space, in this way:

m_pPoseableMeshComp->SetBoneRotationByName(strBoneName, qBoneRotation.Rotator(), EBoneSpaces::WorldSpace);

However, for technical reasons, it is mandatory to set the bone rotations for each finger phalanx in LOCAL space, but poseable meshes seems to work only on world space and component space; checking out 'SkinnedMeshComponent.h' there is a 'LocalSpace' enum value on EBoneSpaces::Type... but it's commented.

/** Values for specifying bone space. */

 UENUM()
 namespace EBoneSpaces
 {
     enum Type
     {
         /** Set absolute position of bone in world space. */
         WorldSpace        UMETA(DisplayName = "World Space"),
         /** Set position of bone in components reference frame. */
         ComponentSpace    UMETA(DisplayName = "Component Space"),
         /** Set position of bone relative to parent bone. */
         //LocalSpace        UMETA( DisplayName = "Parent Bone Space" ),
     };
 }

I cannot understand the phrase 'Set position of bone in components reference frame'. It doesn't seem to work as the "replacement" for local space (as if the bone were rotating around the avatar's pivot point). Is there any other way, or a workaround way, to set rotations in local space for a poseable mesh?.

Thanks on advance. : )

1 Answers1

0

I had this issue as well. Sadly the feature was never implemented in the official Unreal Engine code base.

But you can solve it very easily by extending the poseable mesh component like so.

// MyPoseableMeshComponent.h
#pragma once

#include "CoreMinimal.h"
#include "Components/PoseableMeshComponent.h"
#include "MyPoseableMeshComponent.generated.h"

UCLASS(meta = (BlueprintSpawnableComponent))
class ALSUTILS_API UMyPoseableMeshComponent : public UPoseableMeshComponent
{
    GENERATED_BODY()

public:
    UFUNCTION(BlueprintCallable, Category = "Components|PoseableMesh")
    void SetBoneLocalTransformByName(const FName& BoneName, const FTransform& InTransform);

    UFUNCTION(BlueprintCallable, Category = "Components|PoseableMesh")
    const FTransform& GetBoneLocalTransformByName(const FName& BoneName) const;
};


// MyPoseableMeshComponent.cpp
void UMyPoseableMeshComponent::SetBoneLocalTransformByName(const FName& BoneName, const FTransform& InTransform)
{
  if (!SkeletalMesh || !RequiredBones.IsValid())
  {
    return;
  }

  int32 boneIndex = GetBoneIndex(BoneName);
  if (boneIndex >= 0 && boneIndex < BoneSpaceTransforms.Num())
  {
    BoneSpaceTransforms[boneIndex] = InTransform;
    MarkRefreshTransformDirty();
  }
}

const FTransform& UMyPoseableMeshComponent::GetBoneLocalTransformByName(const FName& BoneName) const
{
  static FTransform zeroTransform;
  if (!SkeletalMesh || !RequiredBones.IsValid())
  {
    return zeroTransform;
  }

  int32 boneIndex = GetBoneIndex(BoneName);
  if (boneIndex >= 0 && boneIndex < BoneSpaceTransforms.Num())
  {
    return BoneSpaceTransforms[boneIndex];
  }
  
  return zeroTransform;
}