November 21, 2017

VR 모드에서 발을 통해 이동하는 기능의 통합 과정

저자: Matthieu Vivant

3d러더(3dRudder)는 앉아서 사용할 수 있는 발 기반의 VR 모션 컨트롤러로, 사용자는 씬 속을 이동하면서도 양 손을 자유롭게 오브젝트의 선택, 커스터마이즈, 혹은 이동 등에 사용할 수 있습니다. 언리얼 엔진 4를 위한 플러그인을 3d러더가 지원하는 세 가지 유형의 로코모션(걷기/뛰기, 부양, 비행)을 제공하는 비 VR 게임과 VR 게임을 포함한 다양한 VR 프로젝트에서 테스트해 본 후, 우리는 언리얼 엔진의 VR 모드를 사용해 보기 시작했습니다. 그 즉시 우리는 우리의 플러그인을 이 에디터에 구현해서 씬 속에서 돌아다닐 수 있는 혁신적인 방법을 제공해, 이 굉장한 툴에 가치를 더할 수 있겠다고 생각했습니다. 770_3DRudder_Pic1.jpg 현재 VR 모드의 씬에서 돌아다니는 방법은 핸드 컨트롤러로 환경을 밀거나 당기는 것이지만, 보다 자연스럽게 움직이는 이동 방식을 쓰면 어떨까요? VR 모드에 3d러더를 통합하는 목적은 개발자들에게:

 

  • 씬 속을 직관적인 공중 부양으로 움직이면서 어떤 관측 지점에든 쉽게 도달할 수 있고
  • 특별한 VR 설비 대신 책상에서 계속 일하면서 에디터와 VR 모드를 쉽게 전환할 수 있고
  • 룸 스케일에만 한정되지 않고
  • 핸드 컨트롤러는 오브젝트 선택, 커스터마이즈, 이동만을 맡도록 하는 것입니다.

 

VR 모드 통합과 함께, 우리는 개발자들에게 표준 언리얼 엔진 4 에디터 내에서도 키보드 및 마우스나 조이스틱(X입력)에 더해 발로도 이동을 할 수 있는 능력을 부여했습니다.
VR 모드에 3d러더 통합

3d러더를 VR 모드에 통합하려면, 기존 언리얼 엔진 4 플러그인에 VR 모드를 처리할 특정 코드를 추가해야 했습니다.
770_3DRudder_Pic2.jpg
우리는 에디터 모듈 제작 관련 위키 페이지를 참조해 에디터를 위한 플러그인을 제작했습니다

첫번째 단계는 3d러더 에디터 모듈을 제작하는 것이었습니다:

1. 3dRudder.uproject에 에디터 모듈을 추가합니다:
 
{
 "Name": "_3DRudderEditor",
 "Type": "Editor",
 "LoadingPhase": "PostEngineInit",
 "WhitelistPlatforms": [ "Win64", "Win32" ]
}

2. Unreal Editor (UnrealEd)를 _3dRudderEditor.build.cs에 종속성으로 추가합니다:
 
PublicDependencyModuleNames.AddRange( new string[] {
    "Core", 
    "CoreUObject",      // 액터와 구조를 제공
    "UnrealEd",
});


3. 다음으로부터 상속되는 F3DRudderEditorModule 클래스를 제작합니다:

a. IModuleInterface - 이것을 통해 모듈을 등록, 시작, 중단할 수 있습니다.
b. FTickableEditorObject - 이것을 통해 매 프레임마다 틱을 할 수 있으며, 3dRudder의 입력 축 값을 구하고 뷰포트 카메라를 업데이트도 할 수 있습니다.
 
void F3DRudderEditorModule::Tick(float DeltaTime)
{
    //UE_LOG(_3DRudderEditor, Warning, TEXT("tick %f"), DeltaTime);
    // 3dRudder SDK
    ns3dRudder::CSdk* pSdk = ns3dRudder::GetSDK();
    // Mode : curve
    ns3dRudder::ModeAxis mode = ns3dRudder::ValueWithCurveNonSymmetricalPitch;
    // Curves for each axis (Pitch, Roll, Yaw, UpDown)
    ns3dRudder::CurveArray *curves = new ns3dRudder::CurveArray;
    // Only one device (0)
    uint32 i = 0;
    if (pSdk->IsDeviceConnected(i))
    {
        // Axis : X, Y, Z, rZ
        ns3dRudder::Axis axis;
        // Status of 3dRudder
        ns3dRudder::Status status;
        if (pSdk->GetAxis(i, mode, &axis, curves) == ns3dRudder::Success)
        {
            status = pSdk->GetStatus(i);            
            if ((status == ns3dRudder::InUse || status == ns3dRudder::ExtendedMode) && GetDefault()->bActive)
                UpdateViewportCamera(FVector(axis.m_aY, axis.m_aX, axis.m_aZ), axis.m_rZ);
        }
    }
}

UpdateViewportCamera에서는 FEditorViewportClient 오브젝트를 구해 MoveViewport 함수를 호출합니다. 우리는 언리얼 엔진 4의 소스 코드에 있던 이 함수가 에디터 내에서 게임패드 및 조이스틱으로 카메라를 조종하는 역할을 맡는다는 사실을 알아냈습니다.
 
void F3DRudderEditorModule::UpdateViewportCamera(const FVector& translation, float yaw)
{
    //UE_LOG(_3DRudderEditor, Warning, TEXT("tick %f"), yaw);
    if (translation.IsZero() && yaw == 0)
        return;
    if (GEditor != nullptr && GEditor->GetActiveViewport() != nullptr && GEditor->GetActiveViewport()->GetClient() != nullptr)
    {
        FEditorViewportClient* client = StaticCast(GEditor->GetActiveViewport()->GetClient());      
        if (client != nullptr && !client->Viewport->IsPlayInEditorViewport())
        {           
            const FVector speed = GetDefault()->Translation;
            const float speedRotation = GetDefault()->RotationYaw;
            // X Y local
            FVector local(translation.X * speed.X, translation.Y * speed.Y, 0);
            FVector world = client->GetViewRotation().RotateVector(local);
            // Z world
            world += FVector(0.0f, 0.0f, translation.Z * speed.Z);
            // Pitch Yaw Roll
            FRotator rotation(0, yaw * speedRotation, 0);
            // Move Camera of Viewport with 3dRudder
            client->MoveViewportCamera(world, rotation);
        }
    }
}


4. 우리는 에디터 속성에 다음과 같은 특정 파라미터도 보여주고 저장하기 위해 U3DRudderSettings 클래스도 만들었습니다:

a. 카메라 모션을 활성화/비활성화 하는 불리언
b. X, Y, Z 축 상의 모션 속도/속력을 변경하는 벡터3
c. Z(요)축 상의 회전 속도/속력을 변경하는 플로트
 
UCLASS(config = Editor, defaultconfig)
class U3DRudderSettings : public UObject
{
    GENERATED_BODY()
public:
    U3DRudderSettings(const FObjectInitializer& ObjectInitializer);
    /** Enable/Disable */
    UPROPERTY(EditAnywhere, config, Category = Move)
        bool bActive;
    /** Speed Translation */
    UPROPERTY(EditAnywhere, config, Category = Speed)
        FVector Translation;
    /** Speed Rotation (Yaw) */
    UPROPERTY(EditAnywhere, config, Category = Speed, meta = (DisplayName = "Rotation (Yaw)" ))
        float RotationYaw;
};

이 같은 설정에 액세스 하려면, 편집 -> 에디터 개인 설정 -> 3dRudder -> Viewport 로 가면 됩니다.
770_3DRudder_Pic3.jpg
위 값을 업데이트하면, Config/DefaultEditor.ini에 저장이 됩니다. 이런 방식으로 여러분은 각 프로젝트마다 다른 모션 속도를 가질 수 있습니다.
 
[/Script/_3DRudderEditor.3DRudderSettings]
Translation=(X=1.000000,Y=2.000000,Z=3.000000)
RotationYaw=5.000000
bActive=True

우리는 이 플러그인을 Visual Studio 2015에서 공백 프로젝트 C++에 제작했습니다.
770_3DRudder_Pic4.jpg
전체 코드는 다음 깃허브(GitHub) 링크에 있습니다:
https://github.com/3DRudder/3DRudderSDK_Unreal_Engine

마지막 단계는 이 패키지를 마켓플레이스 팀에 제출하고 언리얼 엔진의 최신 버전들(4.15, 4.16, 4.17, 그리고 4.18)에서 원활하게 작동하는지 확인하는 것이었습니다. 3d러더 플러그인은 이 곳 언리얼 엔진 4 마켓플레이스 코너에서 찾아보실 수 있습니다.

우리가 직면했던 문제
통합은 전반적으로 원활하게 진행되었습니다. 우리가 직면했던 유일한 문제는 뷰포트 카메라를 이동하는 것이었으며, 이에 관련된 정확한 문서나 샘플 코드를 찾을 수 없기 때문이었습니다. 대신 우리는 VR 모드 소스 코드를 참고해 카메라가 게임패드로는 어떻게 움직이는지 알아보았습니다.

플러그인 설치
마지막으로 플러그인 설치 방법과 언리얼 엔진 4로 3d러더를 사용하는 느낌을 다룬 시연 영상을 제작했습니다.

처음에는 에디터와 VR 모드로 3d러더 플러그인을 설치하는 것을 보여준 다음, 0:45에서는 3d러더를 사용해 표준 에디터의 씬에서, 2:57에서는 VR 모드의 씬에서 돌아다니는 모습을 보여줍니다.

언리얼 엔진 특별 제공

우리는 3d러더가 전반적인 언리얼 엔진 4 VR 에디터 경험을 강화시켜줄 것이라고 생각하기에. 언리얼 엔진 개발자 여러분께 3d 러더를 3d러더의 전문 웹사이트에서 다음 2주 동안 99달러나 99유로(정가: 179달러/유로)에 구입할 수 있는 쿠폰을 기꺼이 제공해 드리기로 했습니다. www.3dRudderBusiness.com 사이트에서 UE4SPECIAL3DRUDDER 코드를 사용하시면 됩니다.