VR 폰 손 카메라뿐

VR 캐릭터 - 몸을 다룰려고

 

Actor, Pawn, Character

- AActor : TF갖고 있어, 월드(레벨)에 배치가 가능

- APawn : 사용자 입력 받음

- ACharacter : 동작(걷기, 뛰기, 점프, 비행 등), 애니메이션

 

 

VRPawn, VRCharacter 차이

- USceneComponent 대신 UCapsuleComponent

- USkeletalMesh Component 추가

 

 

 

 

 

VRPlayer 만들기

Acharacter 상속

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "VRPlayer.generated.h"

UCLASS()
class KDT_VR_API AVRPlayer : public ACharacter
{
	GENERATED_BODY()

public:
	// Sets default values for this character's properties
	AVRPlayer();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;

	// Called to bind functionality to input
	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;


	UPROPERTY(VisibleAnywhere, Category="MySettings|Components")
	class UCameraComponent* cameraComp;

	UPROPERTY(VisibleAnywhere, Category = "MySettings|Components")
	class UStaticMeshComponent* headMesh;

	UPROPERTY(VisibleAnywhere, Category = "MySettings|Components")
	class UMotionControllerComponent* leftMotion;
	UPROPERTY(VisibleAnywhere, Category = "MySettings|Components")
	class UMotionControllerComponent* rightMotion;

	UPROPERTY(VisibleAnywhere, Category = "MySettings|Components")
	class USkeletalMeshComponent* leftHand;
	UPROPERTY(VisibleAnywhere, Category = "MySettings|Components")
	class USkeletalMeshComponent* rightHand;




};

 

 

// Fill out your copyright notice in the Description page of Project Settings.


#include "VRPlayer.h"
#include "Components/StaticMeshComponent.h"
#include "Components/SkeletalMeshComponent.h"
#include "Camera/CameraComponent.h"
#include "MotionControllerComponent.h"


// Sets default values
AVRPlayer::AVRPlayer()
{
 	// Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

	cameraComp = CreateDefaultSubobject<UCameraComponent>(TEXT("CameraComp"));
	cameraComp->SetupAttachment(RootComponent);

	headMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("HeadMesh"));
	headMesh->SetupAttachment(cameraComp);

	leftMotion = CreateDefaultSubobject<UMotionControllerComponent>(TEXT("Left Motion Controller"));
	leftMotion->SetupAttachment(RootComponent);
	leftMotion->MotionSource = FName("Left");

	leftHand = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Left Hand Mesh"));
	leftHand->SetupAttachment(leftMotion);
	leftHand->SetRelativeRotation(FRotator(0, 0, 90));

	rightMotion = CreateDefaultSubobject<UMotionControllerComponent>(TEXT("Right Motion Controller"));
	rightMotion->SetupAttachment(RootComponent);
	rightMotion->MotionSource = FName("Right");

	rightHand = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Right Hand Mesh"));
	rightHand->SetupAttachment(rightMotion);
	rightHand->SetRelativeRotation(FRotator(0, 0, 90));


}

// Called when the game starts or when spawned
void AVRPlayer::BeginPlay()
{
	Super::BeginPlay();
	
}

// Called every frame
void AVRPlayer::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}

// Called to bind functionality to input
void AVRPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);

}

 

 

 

head mesh 설정

 

 

 

헤드셋 쓴상태에선 로그보기 힘듬

 

왼쪽손 로그는 왼쪽위

 

로그를 매시로 띄울수 있음

UTextRenderComponent

 

 

 

 

 

 

 

 

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "VRPlayer.generated.h"

UCLASS()
class KDT_VR_API AVRPlayer : public ACharacter
{
	GENERATED_BODY()

public:
	// Sets default values for this character's properties
	AVRPlayer();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;

	// Called to bind functionality to input
	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;


	UPROPERTY(VisibleAnywhere, Category="MySettings|Components")
	class UCameraComponent* cameraComp;

	UPROPERTY(VisibleAnywhere, Category = "MySettings|Components")
	class UStaticMeshComponent* headMesh;

	UPROPERTY(VisibleAnywhere, Category = "MySettings|Components")
	class UMotionControllerComponent* leftMotion;
	UPROPERTY(VisibleAnywhere, Category = "MySettings|Components")
	class UMotionControllerComponent* rightMotion;

	UPROPERTY(VisibleAnywhere, Category = "MySettings|Components")
	class USkeletalMeshComponent* leftHand;
	UPROPERTY(VisibleAnywhere, Category = "MySettings|Components")
	class USkeletalMeshComponent* rightHand;

	
	UPROPERTY(VisibleAnywhere, Category = "MySettings|Components")
	class UTextRenderComponent* leftLog;
	UPROPERTY(VisibleAnywhere, Category = "MySettings|Components")
	class UTextRenderComponent* rightLog;


};

 

// Fill out your copyright notice in the Description page of Project Settings.


#include "VRPlayer.h"
#include "Components/StaticMeshComponent.h"
#include "Components/SkeletalMeshComponent.h"
#include "Camera/CameraComponent.h"
#include "MotionControllerComponent.h"
#include "Components/TextRenderComponent.h"

// Sets default values
AVRPlayer::AVRPlayer()
{
 	// Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

	cameraComp = CreateDefaultSubobject<UCameraComponent>(TEXT("CameraComp"));
	cameraComp->SetupAttachment(RootComponent);

	headMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("HeadMesh"));
	headMesh->SetupAttachment(cameraComp);

	leftMotion = CreateDefaultSubobject<UMotionControllerComponent>(TEXT("Left Motion Controller"));
	leftMotion->SetupAttachment(RootComponent);
	leftMotion->MotionSource = FName("Left");

	leftHand = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Left Hand Mesh"));
	leftHand->SetupAttachment(leftMotion);
	leftHand->SetRelativeRotation(FRotator(0, 0, 90));

	rightMotion = CreateDefaultSubobject<UMotionControllerComponent>(TEXT("Right Motion Controller"));
	rightMotion->SetupAttachment(RootComponent);
	rightMotion->MotionSource = FName("Right");

	rightHand = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Right Hand Mesh"));
	rightHand->SetupAttachment(rightMotion);
	rightHand->SetRelativeRotation(FRotator(0, 0, 90));

	leftLog = CreateDefaultSubobject<UTextRenderComponent>(TEXT("Left Log"));
	leftLog->SetupAttachment(leftMotion);
	rightLog = CreateDefaultSubobject<UTextRenderComponent>(TEXT("Right Log"));
	rightLog->SetupAttachment(rightMotion);

 

 

 

 

 

 

텍스트수정가능

근데 텍스트가 카메라와 같은 방향

 

손목위치 기준 

 

 

 

 

 

yaw 180도 뒤집을때

 

 

 

 

 

 

 

모션을 옆으로보냄

 

 

 

 

 

 

 

 

 

 

 

 

 

손위치 조정

 

 

 

 

 

 

 

이벤트 추가

 

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "InputActionValue.h"
#include "VRPlayer.generated.h"


	UPROPERTY(EditAnywhere, Category = "MySettings|Inputs")
	class UInputMappingContext* vrMapping;
	UPROPERTY(EditAnywhere, Category="MySettings|Inputs")
	class UInputAction* rightTriggerTouch;

private:
	//트리거 함수, 델리게이터 형식
	void RightTriggerTouch(const FInputActionValue& val);

};

 

 

// Called to bind functionality to input
void AVRPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);

	UEnhancedInputComponent* enhancedInputCopmonent = Cast<UEnhancedInputComponent>(PlayerInputComponent);

	if (enhancedInputCopmonent != nullptr)
	{
		//enhancedInputCopmonent->BindAction();
	}
}


void AVRPlayer::RightTriggerTouch(const FInputActionValue& val)
{


}

 

 

 

언리얼 델리게이터, 시그니처, 바인딩


1. 델리게이터 (Delegate):
   - 델리게이터는 이벤트를 선언하고 호출하기 위한 개체입니다.
   - 다른 함수들을 여러 개 등록하고, 이벤트가 발생할 때 등록된 함수들을 호출할 수 있습니다.
   - 예를 들어, 특정 상황에 대한 이벤트가 발생할 때, 여러 함수들이 실행되어야 할 때 유용하게 사용됩니다.

2. 시그니처 (Signature):
   - 시그니처는 델리게이터에 등록되는 함수의 형식을 정의하는 것입니다.
   - 함수의 매개변수와 반환 값의 형식을 지정하여 델리게이터와 함수가 상호작용할 수 있도록 합니다.
   - 예를 들어, 함수가 인자로 정수를 받고, 부울 값을 반환하는 경우 시그니처는 "(int32, bool)"와 같이 정의됩니다.

3. 바인딩 (Binding):
   - 바인딩은 델리게이터와 함수를 연결하는 과정입니다.
   - 델리게이터에 함수를 바인딩하여 이벤트가 발생할 때 해당 함수가 호출되도록 설정합니다.
   - 바인딩은 런타임 중에 동적으로 수행될 수도 있고, 블루프린트나 C++ 코드에서 정적으로 구현될 수도 있습니다.

 

 

UInputMappingContext, UInputAction

- UInputMappingContext와 UInputAction은 언리얼 엔진에서 입력 매핑과 관련된 중요한 클래스입니다. 

1. UInputMappingContext:
   - UInputMappingContext는 입력 매핑을 그룹화하고 관리하기 위한 클래스입니다.
   - 게임 내에서 특정 상황 또는 컨텍스트에서 사용되는 입력 매핑을 정의하고 관리할 수 있습니다.
   - 예를 들어, "게임 플레이"와 "메뉴"라는 두 가지 컨텍스트에서 서로 다른 입력 매핑을 정의하고 관리할 수 있습니다.
   - UInputMappingContext를 사용하여 특정 컨텍스트에 대한 입력 처리 규칙을 설정하고, 해당 컨텍스트에서 사용되는 UInputAction들을 관리할 수 있습니다.

2. UInputAction:
   - UInputAction은 사용자의 입력에 대한 액션을 정의하는 클래스입니다.
   - 키보드, 마우스, 게임패드 등 다양한 입력 장치로부터의 입력을 처리할 수 있습니다.
   - UInputMappingContext 내에서 사용되며, 특정 입력에 대한 액션을 정의하고 해당 액션을 처리하는 함수를 바인딩할 수 있습니다.
   - 예를 들어, "점프"라는 UInputAction을 정의하여 특정 키 또는 버튼 입력에 대한 점프 동작을 처리할 수 있습니다.

 

InputMappincSubsystem에 대해

// InputMapping Context 파일을 입력 서브시스템에 등록하는 
// 베이스 시스템, 기기별로 다른부분은 서브시스템으로
// 인풋맵핑 컨텍스트를 연결하는 이유는 여러종류로 만들어서 쓸수있도록 하기위함.
// 이전엔 입력체계를 프로젝트 세팅즈에서 해서 런타임중에 바꿀수 없어씅나
// 지금은 인풋맵핑컨텍스트 파일을 따로만들어서 런타임중에 변경 가능하도록 수정됨.
// 캐릭터때 조작법, 차 탔을때 조작법이 바뀐다. => 맵핑 컨텍스트를 변경시켜 구현

 

 

 

 

 

언리얼 인풋시스템에 대해 찾아보다가 잘 정리한 글 찾아서 캡처

 

https://upbo.tistory.com/141

 

 

 

 

 

 

 

 

 

 

 

Input폴더에 다음과 같이 추가

우클릭-input에

inputAction과 inputMappingContext 존재

 

 

 

 

IA_RightIndexTrigger_Touch 벨류는 bool

 

IA_RightIndexTrigger_Press 벨류는 bool

 

IA_RightIndexTrigger_Value의 벨류는 float (눌림정도

 

 

 

IMC_MyVRInputMap은

IA_RightIndexTrigger_Touch/Press/Value 추가

각각 oculus touch trigger 설정

 

 

 

 

VR인풋 파일을 PMI_VRTemplate로 프로젝트 셋팅즈에서 설정

 

 

PMI_VRTemplate는 여기애

 

 

 

 

 

여기서 IMC_MyVRInputMap 추가

 

 

 

 

 

VR플레이어 헤더파일에 인풋맵핑콘택스트, 액션, 바인딩함수 추가

 

	UPROPERTY(EditAnywhere, Category = "MySettings|Inputs")
	class UInputMappingContext* vrMapping;
	UPROPERTY(EditAnywhere, Category="MySettings|Inputs")
	class UInputAction* rightTriggerTouch;
	UPROPERTY(EditAnywhere, Category = "MySettings|Inputs")
	class UInputAction* rightTriggerPress;
	UPROPERTY(EditAnywhere, Category = "MySettings|Inputs")
	class UInputAction* rightTriggerValue;

private:
	//트리거 함수, 델리게이터 형식
	void RightTriggerTouch(const FInputActionValue& val);
	void RightTriggerPress(const FInputActionValue& val);
	void RightTriggerValue(const FInputActionValue& val);

 

 

 

 

비긴플레이에

플레이어 컨트롤러로부터 컨트롤러 가져와서 vrMapping 등록

뒤에 셋업플레이어인풋컴포넌트에서 바인딩 액션 정리

 

 

// Fill out your copyright notice in the Description page of Project Settings.


#include "VRPlayer.h"
#include "Components/StaticMeshComponent.h"
#include "Components/SkeletalMeshComponent.h"
#include "Camera/CameraComponent.h"
#include "MotionControllerComponent.h"
#include "Components/TextRenderComponent.h"

#include "EnhancedInputComponent.h"
#include "EnhancedInputSubsystems.h"

// Sets default values
AVRPlayer::AVRPlayer()
{
 	// Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

	cameraComp = CreateDefaultSubobject<UCameraComponent>(TEXT("CameraComp"));
	cameraComp->SetupAttachment(RootComponent);

	headMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("HeadMesh"));
	headMesh->SetupAttachment(cameraComp);

	leftMotion = CreateDefaultSubobject<UMotionControllerComponent>(TEXT("Left Motion Controller"));
	leftMotion->SetupAttachment(RootComponent);
	leftMotion->MotionSource = FName("Left");

	leftHand = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Left Hand Mesh"));
	leftHand->SetupAttachment(leftMotion);
	leftHand->SetRelativeRotation(FRotator(0, 0, 90));

	rightMotion = CreateDefaultSubobject<UMotionControllerComponent>(TEXT("Right Motion Controller"));
	rightMotion->SetupAttachment(RootComponent);
	rightMotion->MotionSource = FName("Right");

	rightHand = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Right Hand Mesh"));
	rightHand->SetupAttachment(rightMotion);
	rightHand->SetRelativeRotation(FRotator(0, 0, 90));

	leftLog = CreateDefaultSubobject<UTextRenderComponent>(TEXT("Left Log"));
	leftLog->SetupAttachment(leftMotion);
	leftLog->SetRelativeLocation(FVector(20, 0, 0));
	//									피치 요, 롤
	leftLog->SetRelativeRotation(FRotator(90, 180, 0));
	leftLog->SetHorizontalAlignment(EHTA_Center);
	leftLog->SetVerticalAlignment(EVRTA_TextCenter);
	leftLog->SetWorldSize(20);
	leftLog->SetTextRenderColor(FColor::Yellow);

	rightLog = CreateDefaultSubobject<UTextRenderComponent>(TEXT("Right Log"));
	rightLog->SetupAttachment(rightMotion);
	rightLog->SetRelativeRotation(FRotator(90, 180, 0));
	rightLog->SetHorizontalAlignment(EHTA_Center);
	rightLog->SetVerticalAlignment(EVRTA_TextCenter);
	rightLog->SetWorldSize(20);
	rightLog->SetTextRenderColor(FColor::Yellow);
}

// Called when the game starts or when spawned
void AVRPlayer::BeginPlay()
{
	Super::BeginPlay();

	// InputMapping Context 파일을 입력 서브시스템에 등록하는 
	// 베이스 시스템, 기기별로 다른부분은 서브시스템으로
	// 인풋맵핑 컨텍스트를 연결하는 이유는 여러종류로 만들어서 쓸수있도록 하기위함.
	// 이전엔 입력체계를 프로젝트 세팅즈에서 해서 런타임중에 바꿀수 없어씅나
	// 지금은 인풋맵핑컨텍스트 파일을 따로만들어서 런타임중에 변경 가능하도록 수정됨.
	// 캐릭터때 조작법, 차 탔을때 조작법이 바뀐다. => 맵핑 컨텍스트를 변경시켜 구현

	// 입력 서브시스템을 갖고 있는것 - 플레이어 컨트롤러 
	// 플레이어 컨트롤러로부터 입력 서브시스템을 가져옴. getSubsystem() 함수 있음 누구로부터가져올


	//InputMapping Context 파일을 입력 서브시스템에 등록하는 절차 진행
	APlayerController* pc = GetController<APlayerController>();

	if (pc != nullptr)
	{

		UEnhancedInputLocalPlayerSubsystem* subsys = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>
			(pc->GetLocalPlayer());
		subsys->AddMappingContext(vrMapping, 0);

	}

}

// Called every frame
void AVRPlayer::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}

// Called to bind functionality to input
void AVRPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);

	UEnhancedInputComponent* enhancedInputCopmonent = Cast<UEnhancedInputComponent>(PlayerInputComponent);

	if (enhancedInputCopmonent != nullptr)
	{
		// 입력 컴포넌트에 RightTriggerTouch() 함수 연결. (손댔을때, 손땟을때도)
		enhancedInputCopmonent->BindAction(rightTriggerTouch, ETriggerEvent::Started, this, &AVRPlayer::RightTriggerTouch);
		enhancedInputCopmonent->BindAction(rightTriggerTouch, ETriggerEvent::Completed, this, &AVRPlayer::RightTriggerTouch);


		enhancedInputCopmonent->BindAction(rightTriggerPress, ETriggerEvent::Started, this, &AVRPlayer::RightTriggerPress);
		enhancedInputCopmonent->BindAction(rightTriggerPress, ETriggerEvent::Completed, this, &AVRPlayer::RightTriggerPress);
		
		enhancedInputCopmonent->BindAction(rightTriggerValue, ETriggerEvent::Triggered, this, &AVRPlayer::RightTriggerValue);


	}


}


void AVRPlayer::RightTriggerTouch(const FInputActionValue& val)
{
	FString result = val.Get<bool>() == true ? FString("True") : FString("False");
	rightLog->SetText(FText::FromString(FString::Printf(TEXT("Right index touch : %s"), *result)));

}

void AVRPlayer::RightTriggerPress(const FInputActionValue& val)
{
	FString result = val.Get<bool>() == true ? FString("True") : FString("False");
	rightLog->SetText(FText::FromString(FString::Printf(TEXT("Right index pressed : %s"), *result)));
}

void AVRPlayer::RightTriggerValue(const FInputActionValue& val)
{
	float pressed = val.Get<float>();
	rightLog->SetText(FText::FromString(FString::Printf(TEXT("Right index Value : %.3f"), pressed)));
}

 

 

 

마지막으로 VR 플레이어에 액션들 등록

 

결과물

 

 

 

 

+ Recent posts