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 플레이어에 액션들 등록

 

결과물

 

 

 

 

vr setup

1. oculus link sdk

2. android studio - sdk, jdk, ndk

3. stream vr

4. meta app 스마트폰

 

 

jdk 설치

13

https://www.oracle.com/java/technologies/javase/jdk13-archive-downloads.html

 

Java Archive Downloads - Java SE 13

WARNING: These older versions of the JRE and JDK are provided to help developers debug issues in older systems. They are not updated with the latest security patches and are not recommended for use in production. For production use Oracle recommends downlo

www.oracle.com

jdk 설치경로

C:\Program Files\Java\jdk-13.0.2

 

 

 

 

 

안드로이드 스튜디오 설치

 

 

 

 

 

sdk 위치 따로 놓기

C:\Users\addinedu\AppData\Local\Android\Sdk

 

 

 

 

플랫폼 안드로이드 12 설정

 

 

sdk툴에서 sdk빌드툴 31버전으로 설정

 

ndk는 25.1

 

커맨드라인툴은 최신

 

 

 

 

 

c++

character로 VRPlayer 추가

 

 

VRPlayer

 

 "EnhancedInput", "HeadMountedDisplay", "XRBase", "UMG" 

 

추가 후 빌드

안되면 언리얼 끄고, vs 재시작후 다시시도

 

 

 

모듈 추가후 generate visual studio project files

 

언리얼에서 링크해서 쓰기위해 steam vr 사용

 

 

 

스팀VR 할때 유선으로 링크해야함

 

 

 

 

안드로이드 플랫폼 설정

 

 

 

sdk 설정

ndk가 25이므로 

ndk api level을 26에서 25로 수정

 

 

empty 프로젝트로 만들땐

프로젝트-서포트 플랫폼, 타겟하드웨어 설정 필요

 

 

 

 

 

기본맵생성

 

빛강도 2

 

 

안개파란색

 

vrgamemodebase cpp 추가

 

 

 

블루프린트 생성

게임모드에서 디폴트폰 설정

 

 

디폴트게임모드 생성한걸로 변경

맵도 생성한  맵 설정

 

+ Recent posts