유니티6가 나오면서
큰 변화 중에 하나라고 한다면 본격적으로
WebGL 을 모바일웹도 지원해 준다는 것이다.
게다가 미지원 되었던 쉐이더들도 등등
WebGL에 어느정도 진심이 되어버린 유니티.
웹페이지나 앱에서도 유니티 3D를 포함하는 웹, 앱들이
많아지고 있는데
일단 오늘은 유니티 WebGL을 단독 웹이 아닌
React.js에서 넣어서 사용해보자.
나는 React.js가 편해서 리액트를 사용했지만
사실 바닐라로도 되고, Vue.js에서도 방식은 똑같다.
일단 유니티를 작성하기 전 리액트 프로젝트를 만들어보자.
https://www.npmjs.com/package/react-unity-webgl
react-unity-webgl
React Unity WebGL provides a modern solution for embedding Unity WebGL builds in your React Application while providing advanced APIs for two way communication and interaction between Unity and React.. Latest version: 9.6.0, last published: 2 months ago. S
www.npmjs.com
우리가 사용할 리액트 / 유니티 라이브러리 이다.
문서를 보다보면
간단하게 vite(비트)로 시작하라고 한다.
간단히 설명하자면 리액트나 뷰 등의 프론트앤드 개발을 할 때
랜더링을 좀 더 빠르게 해주는 도구라고 보면된다..
이를 설치하려면 node.js 의 npm이 우선 있어야한다.
node가 깔려있다하더라도..
버전이 16.17 이하라면
file:///D:/WebGLBlog/unity-webgl-project/node_modules/vite/dist/node/chunks/dep-yUJfKD1i.js:3
import fsp, { constants as constants$9 } from 'node:fs/promises';
^^^^^^^^^
SyntaxError: The requested module 'node:fs/promises' does not provide an export named 'constants'
at ModuleJob._instantiate (node:internal/modules/esm/module_job:127:21)
at async ModuleJob.run (node:internal/modules/esm/module_job:191:5)
at async Promise.all (index 0)
이런 에러를 보게 될 것이다.
Node.js — 어디서든 JavaScript를 실행하세요
Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine.
nodejs.org
설치해주도록 하자.
대충 next하고 엔터만 누르면 설치가 된다.
그럼 이제 vite로 react.js를 설치해주도록 하자.
프로젝트를 설치할 곳의 터미널에서
npm create vite@latest
우리는 react로
나는 TypeScript를 익숙치 않기도 하고..
유니티가 주인 프로젝트이기 때무넹 JavaScript로 정했다.
완성..
npm run dev
실행해보면 페이지가 나오게 된다.
그럼 이후에
npm i react-unity-webgl
를 하여 라이브러리 설치만 해주고 유니티로 가보자.
자 그럼 유니티로 돌아가자.
유니티6가 나온김에 Unity6로 프로젝트를 생성해보겠다.
2D든 3D든 일단 만들고 제일 먼저 할 것은
.jslib 파일을 만드는 것이다.
이 .jslib 파일은 Plugins 폴더 (필수)에 반드시 만들어주도록하자.
vscode혹은 메모장으로 쉽게 확장자를 .jslib로 만들 수 있다.
이 .jslib의 역할은 유니티와 React.js의 징검다리 역할을 해줄 것이다.
물론 React에서 유니티로 메시지를 보낼 때는 필요 없지만
유니티에서 Web으로 메시지를 보내려면 반드시 필요하다.
난 UnityCallLib.jslib라고 지었고 내용은 다음과 같다.
mergeInto(LibraryManager.library, {
SendMessageToReact : function (msg){
window.dispatchReactUnityEvent(
"OnMessageReceived",
UTF8ToString(msg)
)
},
})
여러개의 함수를 적고 해당 함수들을 호출 하는 방식은
너무 번거롭다.
차라리 하나의 json을 받는 함수를 만들고 각기 리액트와
유니티에서 해당 경우의 수를 나누어주는게 통신구조를 짤 때
더 편하다.
이제 유니티에서 리액트를 호출 할 때는 SendMessageToReact라는 함수가 호출될 것이다.
function (msg)의 msg는 json값이 들어가게 될 것이다.
간단히 UI 정도만 버튼과 TMPro를 이용하여 텍스트 하나만 세팅하고
MessageManager.cs 를 만들자.
스크립팅을 하기 전
json을 사용하기 위하여
Newtonsoft.Json을 설치해주어야 한다.
이 라이브러리는 유니티 버전마다 설치가 되어 나오는 버전이 있고 없고가 있는데;;; (이상하다이건;)
6에는 기본설치가 아닌가보다
Package Manager에서 .
Install Package by name으로
com.unity.nuget.newtonsoft-json
를 적어주면 설치가된다. 설치법 참고는
[unity/json]Newtonsoft Json 라이브러리 손쉽게 추가하는법(package manager 이용)
[unity/json]Newtonsoft Json 라이브러리 손쉽게 추가하는법(package manager 이용) [핵심] com.unity.nuget.newtonsoft-json [windows]->[package manager]로 이동 후 [add pakaage by name...] 선택 com.unity.nuget.newtonsoft-json 를 입력 후
gofogo.tistory.com
다 되었으면 MessageManager.cs를 연다.
기본적으로 메시지매니저는 어느 씬에서든 존재해야 하기에
싱글톤으로 설정하는게 좋지만 데모이기 때문에 하나의 씬에서만 테스트해보자.
MessageManager.cs
using UnityEngine;
using System.Runtime.InteropServices;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
//유니티와 React의 통신을 위한 데이터 클래스
public class UnityDataMessage
{
public string name; //어떤 데이터인지 설명하는 부분 (Enum으로 바꾸어 쓰도록 )
public JObject data; //실제 데이터들
}
public class MessageManager : MonoBehaviour
{
//앞서 적어준 .jslib의 함수이름과 일치해야 한다.
[DllImport("__Internal")]
private static extern void SendMessageToReact(string msg);
/* 이게 우리의 .jslib 파일 이었다.
mergeInto(LibraryManager.library, {
SendMessageToReact : function (msg){
window.dispatchReactUnityEvent(
"OnMessageReceived",
UTF8ToString(msg)
)
},
})
*/
public void ReceiveMessage(string json)
{
UnityDataMessage jsonData = JsonConvert.DeserializeObject<UnityDataMessage>(json);
Debug.Log(jsonData);
JObject jobj = jsonData.data;
Debug.Log($"Event Name : {jsonData.name} Data : {jobj}");
}
private void SendMessage(string n, JObject data)
{
var json = new JObject();
json.Add("name",n);
json.Add("data",data);
SendMessageToReact(json.ToString());
}
public void OnButton_TestSend()
{
JObject test = new JObject();
test.Add("ToReact","myTest");
test.Add("ToReact2","myTest2");
SendMessage("IamdduR",test);
}
}
Send와 Receive를 구현하였다.
테스트를 위한 SendMessage호출부도 구현해두었으니
씬에서 만들어둔 버튼과 연결시켜놓자.
[SerializeField] private TextMeshProUGUI txt_ReceiveInfo;
...
public void ReceiveMessage(string json)
{
UnityDataMessage jsonData = JsonConvert.DeserializeObject<UnityDataMessage>(json);
Debug.Log(jsonData);
JObject jobj = jsonData.data;
txt_ReceiveInfo.text = $"Receive Data : {jsonData}"; //추가
Debug.Log($"Event Name : {jsonData.name} Data : {jobj}");
}
private void SendMessage(string n, JObject data)
{
var json = new JObject();
json.Add("name",n);
json.Add("data",data);
Debug.Log("SendMessage To React"); //추가
SendMessageToReact(json.ToString());
}
링크 연결을 하고 좀 크게 만들어두자
마지막으로 Platform을 Web으로 바꾼 후
ProjectSetting - Player - Publishing Settings로 가서
다음과 같이 세팅해주자
빌드를 하자.
첫빌드는 조금 시간이 걸린다..
이런 파일들이 나오게 된다.
참고로 앞의 Build는 폴더이름을 따른다
난 Build라는 폴더 안에다가 빌드를 했기에 저리 나왔다.
이제 React.js로 다시 돌아가자
public폴더에 Build폴더를 만들고
빌드된 유니티 파일 4개를 넣어준다.
이제 App.jsx를 작성한다.
import { useCallback, useEffect, useState } from 'react';
import { Unity , useUnityContext } from "react-unity-webgl";
import './App.css'
class UnityMessage {
constructor(name, data) {
this.name = name;
this.data = data;
}
}
//Unity의 메시지모델과 동일하게 맞추었다.
const App = () => {
const { unityProvider,sendMessage, addEventListener, removeEventListener,
isLoaded, loadingProgression } = useUnityContext({
loaderUrl: "Build/Build.loader.js",
dataUrl: "Build/Build.data.unityweb",
frameworkUrl: "Build/Build.framework.js.unityweb",
codeUrl: "Build/Build.wasm.unityweb",
});
//라이브러리에서 제공해주는 리스너와 send기능을 선언 . 빌드 파일들을 이름에 맞추어 적어준다.
const [dat, setData] =useState("");
//훅 콜백으로 유니티로부터의 메시지 받는 부분
const ReceiveMsg = useCallback((dat)=>{
setData(dat);
console.log("Receive Success!")
console.log(dat)
},[]);
//훅 리스너 연결 여기서 OnMessageReceived 부분은 .jslib의 string부분과 같아야함
useEffect(() => {
addEventListener("OnMessageReceived",ReceiveMsg);
return() => {
removeEventListener("OnMessageReceived",ReceiveMsg);
};
},[addEventListener,removeEventListener,ReceiveMsg]);
//제공해주는 유니티 로딩부분
const loadingPercentage = Math.round(loadingProgression * 100);
const testSend = () => {
//테스트 유니티로 메시지 보내기
//(유니티 오브젝트 이름,함수이름, 데이터 (파라미터는 하나이상 안되므로 json을 써준것))
sendMessage("MessageManager","ReceiveMessage", JSON.stringify(message))
}
//테스트데이터 클래스
const message = new UnityMessage('SCENE',{
name: "ViewerScene",
mode: 0
})
return (
<div className='App'>
{isLoaded === false && (
<div className="loading-overlay">
<p>Loading... ({loadingPercentage}%)</p>
</div>
)}
<button onClick={testSend}>ToUNITY</button>
<Unity style={{
width: '100%',
height: '70%',
justifySelf: 'center',
alignSelf: 'center',
}}
unityProvider={unityProvider}
devicePixelRatio={devicePixelRatio}
/>
</div>
);
};
export default App;
npm run dev로 실행을 이제 하게 되면...
우선 유니티 버튼 부터 눌러보자
잘 오는 것을 확인할 수 있다.
이제 리액트 버튼을 눌러보자
역시나 잘 가고 받는 것을 볼 수 있다.
오늘은 좀 길긴한데 Unity6로
React.js 와 쌍방향 통신을 하는 방법에 대해서 알아보았다 퓨
WebGL의 전성시대가 열리길..
모르겠는 부분은 댓글..로 문의를...
이 부분은 git이 없다..
하나 생성해 두어야겠다..
'프로그래밍 > Unity' 카테고리의 다른 글
[유니티] Unity - Parallel 병렬처리로 반복작업 속도 향상시키기 (0) | 2024.12.18 |
---|---|
[유니티] Unity - 코루틴 리턴값 받기와 Action에 대하여. (6) | 2024.12.13 |
[유니티] Unity - NewInputSystem 새로운 인풋시스템 적용하기. (0) | 2024.12.10 |
Unity - Rest API 만들고 적용하기 (0) | 2024.12.09 |
유니티 3D - 인공지능 AI (스크립트) (1) | 2017.12.09 |