今回実装したこと
Unity ⇆ API gateway ⇆ Lambda ⇆ DynamoDB ⇆ S3
S3上に置いた画像データをおき、そこに至るパスをDynamoDB上にストックし、Unityからの入力をキッカケにAPI gatewayを経由してLambdaを起動して、入力情報に応じてDynamoDBから必要なS3のパスを返す実装を完成しました。
文字だけだと呪文にしか聞こえないので、実際に動いているところを共有します。
UnityでAWSのサービスを使用する場合、余計なSDKやプラグインなどを使用せず、あくまでAWSのサービスのみで完結する方法についてまとめました。
これができれば、フロントサイドは別にUnityじゃなくてもさまざまなサービスを利用することが可能です。
注意点
AWSの使用は従量課金制となりますので、ここから先を進んだ場合に使用量が発生する可能性があります。そのため、ここから先に進んで費用が発生しても自己責任でお願いいたします。
AWS側の設定
AWSへのログイン
他の記事やgoogleで検索し、AWSのコンソール画面まで進んでください。
S3の設定
まずは、動画ファイルを置いておく場所をS3上に作成します。
バケットの作成
バケットパブリック設定
個別のURLを叩くだけで動画が見られるようにするために、下記のように設定しパブリックアクセスを許可します。
バケットポリシーの部分に下記のスクリプトを貼り付けます。
スクリプト内の'bucket name'は今回作成したバケット名に変更してください。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": [
"s3:GetObject"
],
"Resource": [
"arn:aws:s3:::<bucket nameを入れてください>/*"
]
}
]
}
動画のアップロード
作成されたURLをコピーして、
ブラウザに貼り付けると…、
無事に動画が流れます。
DynamoDBの設定
続いて、先ほど作成した動画につながるS3のURLをためておくデータベースをDynamoDBに作成します。
テーブルの作成
DynamoDBでは作成するデータベースをテーブルと呼びます。
下記の画像を参考にテーブルを作成します。
データの更新方法
下記の手順でノーコードでDynamoDB上のデータの更新・登録が可能です。
Lambdaの設定
次に、DynamoDBからデータを引き出すために、Lambdaというサービス上に関数を作成し、UnityからLambdaに刺激が入ると関数が起動するように設定を行います。
IAMの設定
まず初めに、LamdbaがDynamoDBの内容にアクセスできるようにIAMで権限を設定します。
下記を参考にDynamoDBとCloudWatchのFullAccessのポリシーを持つロールを作成してください。
Lambdaの設定
Lambdaに移動して関数を作成します。
コードソースのindex.jsの部分に下記のコードを貼り付け、Deployを押します。
const AWS = require('aws-sdk')
const client = new AWS.DynamoDB.DocumentClient()
/**
* API Gatewayを通してリクエストから受け取ったユーザーID、動画IDと一致するitemを取得して返却するLambda
*
* @param {*} event APIGatwayからわたってくるパラメーターがこのevent引数を通して渡される
* GETリクエストにおけるクエリはqueryStringParametersというプロパティに設定されている
* @returns
*/
exports.handler = async (event)=>{
console.log("event", event);
const DoctorID = event.Keys.DoctorID;
const MovieID = event.Keys.MovieID;
/**
* ハッシュキー:userId、ソートキー:movieIdというDynamoDBテーブルを想定している
*/
const result = await client.query({
TableName:'MoviesDB',
KeyConditionExpression:'#DoctorID = :DoctorID AND begins_with(#MovieID , :MovieID)',
ExpressionAttributeNames:{
'#DoctorID':'DoctorID',
'#MovieID':'MovieID'
},
ExpressionAttributeValues:{
':DoctorID':DoctorID,
':MovieID':MovieID,
}
}).promise()
const items = result.Items
return {
statusCode:200,
body:items
}
}
ロールの設定
名前は適宜設定し、ロール部分に先ほど作成したロールを割り当てます。
API Gatewayの設定
最後に、Unityからの刺激をLambdaに伝える通り道であるAPIをAPI Gatewayで作成します。
APIの作成
下記の図を参考にAPIを作成します。
今回はREST APIを作成します。
Unity側の設定
最後にUnity側から動画を呼び出す設定を行います。
動画を映す板の作成
動画のはめ込みに関しては他の記事に譲ります。
流れは以下の通りです。
① 3D planeを作成
② videoplayerのオブジェクトを作成
③ render textureを作成
④ materialを作成
⑤ 作成したmaterialに作成したrender textureをアタッチ
⑥ 3D planeにmaterialをアタッチ
⑦ videoplayerコンポーネントにrender textureをアタッチ
VideoPlayerのスクリプト
下記のスクリプトをVideoPlayerオブジェクトにアタッチします。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Video;
public class VideoPlayerManager : MonoBehaviour
{
VideoPlayer video;
public List<string> URLs = new List<string>();
public void VideoPlay(int num)
{
video = gameObject.GetComponent<VideoPlayer>();
video.playOnAwake = false;
video.waitForFirstFrame = true;
video.source = VideoSource.Url;
video.url = URLs[num];
video.prepareCompleted += VideoPlayerOnPrepareCompleted;
video.Prepare();
}
private void VideoPlayerOnPrepareCompleted(VideoPlayer source)
{
video.Play();
}
public void OnClickVideoPlay(int num)
{
VideoPlay(num);
}
}
AWSに接続するための設定
下記のスクリプトをからのオブジェクトにアタッチします。
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.Serialization;
using UnityEngine.UI;
public class unitytoaws : MonoBehaviour
{
[SerializeField] private string DoctorID;
[SerializeField] private string MovieID;
[SerializeField] private DynamoResponse response;
[SerializeField] VideoPlayerManager videoPlayerManager;
public string URL;
[Serializable]
public class DynamoIftest
{
public DynamoQueryKey Keys;
[Serializable]
public class DynamoQueryKey
{
public string DoctorID;
public string MovieID;
}
}
[Serializable]
public class DynamoResponse
{
public List<DynamoResponseItems> body;
[Serializable]
public class DynamoResponseItems
{
public string DoctorID;
public string MovieID;
public string URL;
}
}
void Start()
{
StartCoroutine(AwsApiTest());
}
private IEnumerator AwsApiTest()
{
var awsElement = new DynamoIftest()
{
Keys = new DynamoIftest.DynamoQueryKey() { DoctorID = DoctorID, MovieID = MovieID }
};
string jsonStr = JsonUtility.ToJson(awsElement);
var request = new UnityWebRequest();
request.url = "<ApiGatewayで作成したApiのUrl>";
var body = Encoding.UTF8.GetBytes(jsonStr);
request.uploadHandler = new UploadHandlerRaw(body);
request.downloadHandler = new DownloadHandlerBuffer();
request.SetRequestHeader("Content-Type", "application/json");
request.method = UnityWebRequest.kHttpVerbPOST;
yield return request.Send();
if (request.isNetworkError)
{
Debug.Log(request.error); }
else
{
if (request.responseCode == 200)
{
var responseJsonText = request.downloadHandler.text;
Debug.Log(responseJsonText);
response = JsonUtility.FromJson<DynamoResponse>(responseJsonText);
Debug.Log(response.body[0].URL);
URL = response.body[0].URL;
videoPlayerManager.URLs.Clear();
foreach (var item in response.body)
{
videoPlayerManager.URLs.Add(item.URL);
}
}
else
{
Debug.Log("failed");
}
}
}
}
完成形
完成した挙動がこちらです。
UnityからLambdaを刺激して、DynamoDBからS3上にある画像データまでのパスを引っ張ってくる実装が完成!
— Dr.Teru:プログラミングとサーフィンが好きな整形外科医 (@teru3_kitashiro) July 31, 2022
AWSの理解が深まってきた!#protoout#スタジオしまづ#もいせん https://t.co/T46K6szHuy pic.twitter.com/M8zwuLhJ2v
今後もSDKを使用せずに、APIでUnityからAWSを使える実装の勉強を進めていきます。