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 파일을 입력 서브시스템에 등록하는
// 베이스 시스템, 기기별로 다른부분은 서브시스템으로
// 인풋맵핑 컨텍스트를 연결하는 이유는 여러종류로 만들어서 쓸수있도록 하기위함.
// 이전엔 입력체계를 프로젝트 세팅즈에서 해서 런타임중에 바꿀수 없어씅나
// 지금은 인풋맵핑컨텍스트 파일을 따로만들어서 런타임중에 변경 가능하도록 수정됨.
// 캐릭터때 조작법, 차 탔을때 조작법이 바뀐다. => 맵핑 컨텍스트를 변경시켜 구현
언리얼 인풋시스템에 대해 찾아보다가 잘 정리한 글 찾아서 캡처
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 플레이어에 액션들 등록
결과물
'컴퓨터과학 > 언리얼' 카테고리의 다른 글
관성모션 - 3. 언리얼PC와 아두이노 블루투스 통신 (0) | 2024.02.14 |
---|---|
관성모션 - 2. 블루투스 기초통신 (0) | 2024.02.14 |
관성모션 - 1. 이것저것 찾아보기 (0) | 2024.02.13 |
VR기초 - 1. 준비 (0) | 2024.02.13 |
HandDesktop26 - 윈도우API 마우스 제어 연동 (0) | 2024.02.08 |