
이렇게 컨트롤러대로 조준선 표시하고 voxel 만드는 내용

연습용으로 아래 asset 사용
https://assetstore.unity.com/packages/tools/integration/oculus-integration-deprecated-82022
Oculus Integration (Deprecated) | 기능 통합 | Unity Asset Store
Use the Oculus Integration (Deprecated) from Meta on your next project. Find this integration tool & more on the Unity Asset Store.
assetstore.unity.com
다운받고 project settings에서 눌러주기

폴더설정

#ARAVRInput.cs
전처리기를 사용해 작업 환경 전환 가능 -> 각 기능에 해당되는 부분들만 활성화되게
#define앞에 주석을 붙이거나 없애주자
//#define PC
#define Oculus
//#define Vive
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
#if Vive
using Valve.VR;
using UnityEngine.XR;
#endif
public static class ARAVRInput
{
#if PC
public enum ButtonTarget
{
Fire1,
Fire2,
Fire3,
Jump,
}
#elif Vive
public enum ButtonTarget
{
Teleport,
InteractUI,
GrabGrip,
Jump,
}
#endif
public enum Button
{
#if PC
One = ButtonTarget.Fire1,
Two = ButtonTarget.Jump,
Thumbstick = ButtonTarget.Fire1,
IndexTrigger = ButtonTarget.Fire3,
HandTrigger = ButtonTarget.Fire2
#elif Oculus
One = OVRInput.Button.One,
Two = OVRInput.Button.Two,
Thumbstick = OVRInput.Button.PrimaryThumbstick,
IndexTrigger = OVRInput.Button.PrimaryIndexTrigger,
HandTrigger = OVRInput.Button.PrimaryHandTrigger
#elif Vive
One = ButtonTarget.InteractUI,
Two = ButtonTarget.Jump,
Thumbstick = ButtonTarget.Teleport,
IndexTrigger = ButtonTarget.InteractUI,
HandTrigger = ButtonTarget.GrabGrip,
#endif
}
public enum Controller
{
#if PC
LTouch,
RTouch
#elif Oculus
LTouch = OVRInput.Controller.LTouch,
RTouch = OVRInput.Controller.RTouch
#elif Vive
LTouch = SteamVR_Input_Sources.LeftHand,
RTouch = SteamVR_Input_Sources.RightHand,
#endif
}
// 왼쪽 컨트롤러
static Transform lHand;
// 씬에 등록된 왼쪽 컨트롤러를 찾아 반환
public static Transform LHand
{
get
{
if (lHand == null)
{
#if PC
// LHand라는 이름으로 게임 오브젝트를 만든다.
GameObject handObj = new GameObject("LHand");
// 만들어진 객체의 트랜스폼을 lHand에 할당
lHand = handObj.transform;
// 컨트롤러를 카메라의 자식 객체로 등록
lHand.parent = Camera.main.transform;
#elif Oculus
lHand = GameObject.Find("LeftControllerAnchor").transform;
#elif Vive
lHand = GameObject.Find("Controller(left)").transform;
#endif
}
return lHand;
}
}
// 오른쪽 컨트롤러
static Transform rHand;
// 씬에 등록된 오른쪽 컨트롤러 찾아 반환
public static Transform RHand
{
get
{
// 만약 rHand에 값이 없을경우
if (rHand == null)
{
#if PC
// RHand 이름으로 게임 오브젝트를 만든다.
GameObject handObj = new GameObject("RHand");
// 만들어진 객체의 트렌스폼을 rHand에 할당
rHand = handObj.transform;
// 컨트롤러를 카메라의 자식 객체로 등록
rHand.parent = Camera.main.transform;
#elif Oculus
rHand = GameObject.Find("RightControllerAnchor").transform;
#elif Vive
rHand = GameObject.Find("Controller(right)").transform;
#endif
}
return rHand;
}
}
public static Vector3 RHandPosition
{
get
{
#if PC
// 마우스의 스크린 좌표 얻어오기
Vector3 pos = Input.mousePosition;
// z 값은 0.7m로 설정
pos.z = 0.7f;
// 스크린 좌표를 월드 좌표로 변환
pos = Camera.main.ScreenToWorldPoint(pos);
RHand.position = pos;
return pos;
#elif Oculus
Vector3 pos = OVRInput.GetLocalControllerPosition(OVRInput.Controller.RTouch);
pos = GetTransform().TransformPoint(pos);
return pos;
#elif Vive
Vector3 pos = RHand.position;
return pos;
#endif
}
}
public static Vector3 RHandDirection
{
get
{
#if PC
Vector3 direction = RHandPosition - Camera.main.transform.position;
RHand.forward = direction;
return direction;
#elif Oculus
Vector3 direction = OVRInput.GetLocalControllerRotation(OVRInput.Controller.
RTouch) * Vector3.forward;
direction = GetTransform().TransformDirection(direction);
return direction;
#elif Vive
Vector3 direction = RHand.forward;
return direction;
#endif
}
}
public static Vector3 LHandPosition
{
get
{
#if PC
return RHandPosition;
#elif Oculus
Vector3 pos = OVRInput.GetLocalControllerPosition(OVRInput.Controller.LTouch);
pos = GetTransform().TransformPoint(pos);
return pos;
#elif Vive
Vector3 pos = LHand.position;
return pos;
#endif
}
}
public static Vector3 LHandDirection
{
get
{
#if PC
return RHandDirection;
#elif Oculus
Vector3 direction = OVRInput.GetLocalControllerRotation(OVRInput.Controller.LTouch) * Vector3.forward;
direction = GetTransform().TransformDirection(direction);
return direction;
#elif Vive
Vector3 direction = LHand.forward;
return direction;
#endif
}
}
#if Oculus || Vive
static Transform rootTransform;
#endif
#if Oculus
static Transform GetTransform()
{
if (rootTransform == null)
{
rootTransform = GameObject.Find("TrackingSpace").transform;
}
return rootTransform;
}
#elif Vive
static Transform GetTransform()
{
if (rootTransform == null)
{
rootTransform = GameObject.Find("[CameraRig]").transform;
}
return rootTransform;
}
#endif
// 컨트롤러의 특정 버튼을 누르고 있는 동안 true를 반환
public static bool Get(Button virtualMask, Controller hand = Controller.RTouch)
{
#if PC
// virtualMask에 들어온 값을 ButtonTarget 타입으로 변환해 전달한다.
return Input.GetButton(((ButtonTarget)virtualMask).ToString());
#elif Oculus
return OVRInput.Get((OVRInput.Button)virtualMask, (OVRInput.Controller)hand);
#elif Vive
string button = ((ButtonTarget)virtualMask).ToString();
return SteamVR_Input.GetState(button, (SteamVR_Input_Sources)(hand));
#endif
}
// 컨트롤러의 특정 버튼을 눌렀을 때 true를 반환
public static bool GetDown(Button virtualMask, Controller hand = Controller.RTouch)
{
#if PC
return Input.GetButtonDown(((ButtonTarget)virtualMask).ToString());
#elif Oculus
return OVRInput.GetDown((OVRInput.Button)virtualMask, (OVRInput.Controller)hand);
#elif Vive
string button = ((ButtonTarget)virtualMask).ToString();
return SteamVR_Input.GetStateDown(button, (SteamVR_Input_Sources)(hand));
#endif
}
// 컨트롤러의 특정 버튼을 눌렀다 떼었을 때 true를 반환
public static bool GetUp(Button virtualMask, Controller hand = Controller.RTouch)
{
#if PC
return Input.GetButtonUp(((ButtonTarget)virtualMask).ToString());
#elif Oculus
return OVRInput.GetUp((OVRInput.Button)virtualMask, (OVRInput.Controller)hand);
#elif Vive
string button = ((ButtonTarget)virtualMask).ToString();
return SteamVR_Input.GetStateUp(button, (SteamVR_Input_Sources)(hand));
#endif
}
// 컨트롤러의 Axis 입력을 반환
// axis: Horizontal, Vertical 값을 갖는다.
public static float GetAxis(string axis, Controller hand = Controller.LTouch)
{
#if PC
return Input.GetAxis(axis);
#elif Oculus
if (axis == "Horizontal")
{
return OVRInput.Get(OVRInput.Axis2D.PrimaryThumbstick, (OVRInput.Controller)hand).x;
}
else
{
return OVRInput.Get(OVRInput.Axis2D.PrimaryThumbstick, (OVRInput.Controller)hand).y;
}
#elif Vive
if (axis == "Horizontal")
{
return SteamVR_Input.GetVector2("TouchPad", (SteamVR_Input_Sources)(hand)).x;
}
else
{
return SteamVR_Input.GetVector2("TouchPad", (SteamVR_Input_Sources)(hand)).y;
}
#endif
}
// 컨트롤러에 진동 호출하기
public static void PlayVibration(Controller hand)
{
#if Oculus
PlayVibration(0.06f, 1, 1, hand);
#elif Vive
PlayVibration(0.06f, 160, 0.5f, hand);
#endif
}
public static void PlayVibration(float duration, float frequency, float amplitude, Controller hand)
{
#if Oculus
if (CoroutineInstance.coroutineInstance == null)
{
GameObject coroutineObj = new GameObject("CoroutineInstance");
coroutineObj.AddComponent<CoroutineInstance>();
}
// 이미 플레이중인 진동 코루틴은 정지
CoroutineInstance.coroutineInstance.StopAllCoroutines();
CoroutineInstance.coroutineInstance.StartCoroutine(VibrationCoroutine(duration, frequency, amplitude, hand));
#elif Vive
SteamVR_Actions._default.Haptic.Execute(0, duration, frequency, amplitude, (SteamVR_Input_Sources)hand);
#endif
}
// 카메라가 바라보는 방향을 기준으로 센터를 잡는다.
public static void Recenter()
{
#if Oculus
OVRManager.display.RecenterPose();
#elif Vive
List<XRInputSubsystem> subsystems = new List<XRInputSubsystem>();
SubsystemManager.GetInstances<XRInputSubsystem>(subsystems);
for (int i = 0; i < subsystems.Count; i++)
{
subsystems[i].TrySetTrackingOriginMode(TrackingOriginModeFlags.
TrackingReference);
subsystems[i].TryRecenter();
}
#endif
}
// 원하는 방향으로 타깃의 센터를 설정
public static void Recenter(Transform target, Vector3 direction)
{
target.forward = target.rotation * direction;
}
#if PC
static Vector3 originScale = Vector3.one * 0.02f;
#else
static Vector3 originScale = Vector3.one * 0.005f;
#endif
// 광선 레이가 닿는 곳에 크로스헤어를 위치시키고 싶다.
public static void DrawCrosshair(Transform crosshair, bool isHand = true, Controller hand = Controller.RTouch)
{
Ray ray;
// 컨트롤러의 위치와 방향을 이용해 레이 제작
if (isHand)
{
#if PC
ray = Camera.main.ScreenPointToRay(Input.mousePosition);
#else
if (hand == Controller.RTouch)
{
ray = new Ray(RHandPosition, RHandDirection);
}
else
{
ray = new Ray(LHandPosition, LHandDirection);
}
#endif
}
else
{
// 카메라를 기준으로 화면의 정중앙으로 레이를 제작
ray = new Ray(Camera.main.transform.position, Camera.main.transform.forward);
}
// 눈에 안 보이는 Plane을 만든다.
Plane plane = new Plane(Vector3.up, 0);
float distance = 0;
// plane을 이용해 ray를 쏜다.
if (plane.Raycast(ray, out distance))
{
// 레이의 GetPoint 함수를 이용해 충돌 지점의 위치를 가져온다.
crosshair.position = ray.GetPoint(distance);
crosshair.forward = -Camera.main.transform.forward;
// 크로스헤어의 크기를 최소 기본 크기에서 거리에 따라 더 커지도록 한다.
crosshair.localScale = originScale * Mathf.Max(1, distance);
}
else
{
crosshair.position = ray.origin + ray.direction * 100;
crosshair.forward = -Camera.main.transform.forward;
distance = (crosshair.position - ray.origin).magnitude;
crosshair.localScale = originScale * Mathf.Max(1, distance);
}
}
#if Oculus
static IEnumerator VibrationCoroutine(float duration, float frequency, float amplitude, Controller hand)
{
float currentTime = 0;
while (currentTime < duration)
{
currentTime += Time.deltaTime;
OVRInput.SetControllerVibration(frequency, amplitude, (OVRInput.Controller)
hand);
yield return null;
}
OVRInput.SetControllerVibration(0, 0, (OVRInput.Controller)hand);
}
#endif
}
// ARAVRInput 클래스에서 사용할 코루틴 객체
class CoroutineInstance : MonoBehaviour
{
public static CoroutineInstance coroutineInstance = null;
private void Awake()
{
if (coroutineInstance == null)
{
coroutineInstance = this;
}
DontDestroyOnLoad(gameObject);
}
}
vr 링크로 컴퓨터와 연결한 뒤
프로젝트에 OVRCameraRig 넣어주기

floor랑 voxel maker 만들고, 3d cube에 voxel넣어서 프리팹화하기
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Voxel : MonoBehaviour
{
public float speed = 5f;
float destroyTime = 3.0f;
float currentTime;
private void OnEnable()
{
currentTime = 0f;
//랜덤한 방향을 구함
Vector3 direction = Random.insideUnitSphere;
Rigidbody rb = GetComponent<Rigidbody>();
rb.velocity = direction * speed;
}
// Update is called once per frame
void Update()
{
currentTime += Time.deltaTime;
if (currentTime > destroyTime)
{
gameObject.SetActive(false);
VoxelMaker.voxelPool.Add(gameObject);
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class VoxelMaker : MonoBehaviour
{
public GameObject voxelFactory;
public int voxelPoolSize = 20;
public float createTime = 0.1f;
float currentTime = 0f;
public static List<GameObject> voxelPool = new List<GameObject>();
private void Start()
{
for (int i = 0; i < voxelPoolSize; i++)
{
GameObject voxel = Instantiate(voxelFactory);
voxel.SetActive(false);
voxelPool.Add(voxel);
}
}
private void Update()
{
// if (Input.GetButtonDown("Fire1")) //좌클릭
// {
if (ARAVRInput.Get(ARAVRInput.Button.One)) //VR컨트롤러에서 A버튼 누르면
{
currentTime += Time.deltaTime;
if (currentTime > createTime)
{
// Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); //pc버전
Ray ray = new Ray(ARAVRInput.RHandPosition, ARAVRInput.RHandDirection); //오른손 위치에서 오른손 방향으로 Ray쏘기
RaycastHit hitInfo = new RaycastHit();
if (Physics.Raycast(ray, out hitInfo))
{
// GameObject voxel = Instantiate(voxelFactory);
// voxel.transform.position = hitInfo.point;
GameObject voxel = voxelPool[0];
voxel.SetActive(true);
voxel.transform.position = hitInfo.point;
voxelPool.RemoveAt(0);
currentTime = 0f;
}
}
}
}
}
넣어주고 오큘러스에서 실행할때 링크 연결하고 작동하면
controller에서 a 누르면 voxel이 생성된다
조준선으로 쓸 sprite 이미지 생성


ui > image로 만들고, canvas는 world space로 바꿔주기
rect transform 리셋하고 1 1 크기, image는 10 10 크기
z값때문에 물체가 겹쳐보이는 문제
https://github.com/TwoTailsGames/Unity-Built-in-Shaders
defaultResourcesExtra > UI > UI-Default.shader를 crosshair로 이름 바꿔서 애셋 폴더에 넣어주고
subshader에서 ztest always로 바꿔준다




shader 우클릭후 material 만든다 / shader는 crosshair로 설정
조준선 이미지의 material에 넣어주기
voxel maker 코드에
public transform Crosshair선언 > 캔버스 연결

update문에 추가
ARAVRInput.DrawCrosshair(crosshair);

컨트롤러 위치에 맞게 조준선이 보인다

a 누르면 생성완료
'공부 > Unity' 카테고리의 다른 글
[Unity] 컴포넌트 안쓰고 위치, 애니메이션 연동 (Oculus + Photon) (1) | 2025.06.24 |
---|---|
[Unity] Photon Network 포톤 네트워크 Lobby manager 예시 (2) | 2025.06.24 |
[Unity] 포톤 네트워크 / 채팅 스크립트 (0) | 2025.06.18 |
[Unity] NavMesh에서 랜덤한 포인트 얻기 (0) | 2025.06.16 |
[Unity] 유니티 Monobehaviour의 생명주기(Lifecycle) / Monobehaviour의 특징 (0) | 2025.06.12 |