VRC PanoramaをGoogle Apps Scriptで活用する

はじめまして、nyakome（[@nyakome306](https://twitter.com/nyakome306)）といいます。Qiitaはほぼ初投稿です。
これは[VRChat Advent Calendar 2018](https://qiita.com/advent-calendar/2018/vrchat) 10日目の記事です。
解説記事を書くのは初めてなので、読みづらかったり至らない点があると思いますがよろしくお願いします。
#はじめに


　VRChatのコンポーネントの一つであるVRC_Panormaは指定したURLの画像を読み込めるのでVRChat内から外のインターネットを叩いて遊べますが、サーバー用意したくないのでGAS使う話です。  

##何ができるの？
こういうのです。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">GASで表を画像として出力することができたので、GoogleCalendarからイベント情報取ってきてVRC Panoramaで表示させてみる<a href="https://twitter.com/hashtag/VRChat?src=hash&amp;ref_src=twsrc%5Etfw">#VRChat</a> <a href="https://t.co/ayT3gp6yyq">pic.twitter.com/ayT3gp6yyq</a></p>&mdash; にゃこめ (@nyakome_vr) <a href="https://twitter.com/nyakome_vr/status/1069954000798150656?ref_src=twsrc%5Etfw">2018年12月4日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">アニメーションな地球儀<br>ワールドに入った時刻から直近24時間分（30分間隔）の衛星画像を使ってアニメーションしてる<a href="https://twitter.com/hashtag/VRChat?src=hash&amp;ref_src=twsrc%5Etfw">#VRChat</a> <a href="https://t.co/YnUmH15EJ6">pic.twitter.com/YnUmH15EJ6</a></p>&mdash; にゃこめ (@nyakome_vr) <a href="https://twitter.com/nyakome_vr/status/1054343266689212416?ref_src=twsrc%5Etfw">2018年10月22日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

主にGASで指定した日時にURL先の画像を更新して、それをVRC Panoramaで表示して実現してます。


##VRC_Panoramaでできること
　本来はパノラマ画像を表示する用途らしいですが、URL先の画像を読み込んで表示する用途で使ってます。
　PanoramasのテクスチャやURLで指定した画像を表示できて、複数URLを指定するとUnityのコンポーネントのButtonでNextPano()を発火させることで複数の画像を切り替えて表示できます。

技術メモに詳細があります。
https://vrcworld.wiki.fc2.com/wiki/VRC_Panorama






##GoogleAppsScript (GAS)って？
　Googleのサーバー上に実行環境がある、Javascriptを元にした言語
　Google DriveとかスプレッドシートなどのGoogleが提供するサービスを簡単に操作できて、Webアプリとか作れます。
　スクリプトの実行時間等に制限はありますが無料で使えて、他のPaaSと比べると開発環境もブラウザで行えてサクッと作れるのが特徴です。
　今回は主にGASでGoogle Driveを操作します。


#GASとVRC Panoramaの組み合わせ
　先にも少し書きましたが、VRC Panoramaに設定したURL先の画像(Google Drive上の画像)をGASで書き換えて、VRC上で表示される画像を変更するのが主な使い方です。
　この記事では主にVRC Panoramaで表示するため設定とGASを使った画像ファイルの操作について書いていきます。


##VRC Panoramaの設定
VRC Panorama用のマテリアルを新規作成し、UnityのQuadに下の画像のように設定すれば動きます。
![Unity 5.6.3p1 Personal (64bit) - Home_Kit_Assembled.unity - vrchat_home - PC, Mac & Linux Standalone _DX11_ 2018_12_06 9_19_40 (2).png](https://qiita-image-store.s3.amazonaws.com/0/176380/4d1dacc1-2689-25ff-8ba7-6330e80addce.png)

~~そのままだとVRCPanoramaの仕様でガンマ補正が二重に掛かってて画像が普通より明るく表示されてしまいます。逆ガンマ補正を掛けて表示するシェーダーを作ったので置いておきます。~~
~~https://www.dropbox.com/s/2g7e4jc4ss9ea8a/unlit_vrc_panorama.shader?dl=0~~
・12/20追記
 12/12にVRChatがUnity2017.4.15.f1に移行し、そのタイミングでVRCPanoramaのガンマ補正のバグが修正されたため、このシェーダーは必要ありません。

ちなみにVRC PanoramaはVRChatを起動しなくてもUnityのPlay押すだけで動作します。


##GASの導入
以下のURLにアクセスし、左上の新規スクリプトをクリックするとエディタが開きます
https://script.google.com
![12.png](https://qiita-image-store.s3.amazonaws.com/0/176380/443739bf-7fd2-d057-d39a-0972ca2b8a31.png)
![11.png](https://qiita-image-store.s3.amazonaws.com/0/176380/0a63e731-f3d5-56ef-12d2-c020f927e521.png)
####APIの有効化
また今回はDrive APIとGoogle Slides APIを使うため、
リソース→Googleの拡張サービスよりDrive APIとGoogle Slides APIの横のトグル（表示が壊れてますね…）をクリックして有効にしてください。
![15.png](https://qiita-image-store.s3.amazonaws.com/0/176380/9fa1fb5f-86f2-d4db-778a-5685fbe7c9bf.png)
![16.png](https://qiita-image-store.s3.amazonaws.com/0/176380/e87d3eae-79f3-90e4-06af-15db7bfbbd64.png)


####スクリプトの初回実行時
GoogleのAPIを使う場合、スクリプトの実行ボタンを押すと、初回はプロジェクトの認証のためのウィンドウが出ます。使っているアカウントを選択して矢印の通りにクリックしてください。
![5.png](https://qiita-image-store.s3.amazonaws.com/0/176380/3d87609d-232b-b5e5-80ec-15aa078a9422.png)
![6.png](https://qiita-image-store.s3.amazonaws.com/0/176380/fc4aed9c-e758-9b91-d1f2-5094f4bb4119.png)
![7.png](https://qiita-image-store.s3.amazonaws.com/0/176380/6f282534-2afc-b271-24ac-8f43abd1b713.png)
![8.png](https://qiita-image-store.s3.amazonaws.com/0/176380/f262ddda-ef42-1864-2727-6ad01c921278.png)


##Google Driveに置いた画像をVRC Panoramaで表示する
####VRC Panoramaで指定するURL
　上の例は、GoogleDriveに置いた画像ファイルのURLをPanoramasに入力し、ファイルをGASで定期的に更新して実現してます。
　VRC_Panoramaに指定するURLは画像の直リンクでないと表示できないため、直接画像を表示できるリンクを取得します。
　GoogleDriveで画像ファイルを開いて右上のその他の操作→新しいウインドウで開くをクリックすると、URLは以下のようになります。


```
https://drive.google.com/file/d/{ID}/view
```
これを{ID}を用いて、以下のように書き換えたURLをVRC Panoramaのurlに入力すると表示されます。


```
http://drive.google.com/uc?export=view&id={ID}
```
####ファイルの共有設定
またVRChatからアクセスできるようにするため、表示する画像ファイルの共有設定をする必要があります。
ファイルを右クリックして共有→共有可能なリンクを取得をクリックしてください。
※ここで取得したURLはVRC Panoramaでは使えません。

![13.png](https://qiita-image-store.s3.amazonaws.com/0/176380/2ca41ec5-f2df-889c-19a8-8e4a98207918.png)
![14.png](https://qiita-image-store.s3.amazonaws.com/0/176380/3dc29343-280b-e2c9-70b3-b60523f0ea38.png)


##GASを使った画像ファイルの取得、更新
外部サイトからの画像取得と画像ファイル更新部のスクリプトがこちらです。
指定したIDのファイルの中身をimageURL先の画像に書き換えます。

　スクリプトをエディタにコピペして更新するファイルのIDを指定して実行（三角形のやつ）をクリックし、プロジェクトを認証すると動きます。

```
function myFunction() {
  var updateFileId = "更新するファイルのID";
  var imageURL = "https://booth.pximg.net/ed52788c-0b3b-4e38-9ded-1e5797daf0ef/i/922954/ff456ba0-f4ee-4753-8d18-81f229f44b00_base_resized.jpg";
  
  //画像取得
  var image=UrlFetchApp.fetch(imageURL).getBlob();
  
  //画像更新
  updateFileById(DriveApp.getFileById(updateFileId).getName(),updateFileId,image);
}


//指定したidのファイルの内容をblobで上書きする
function updateFileById(title,id,blob) {
  var body = {
    title: title,
    mimeType: 'image/png'
  };
  file = Drive.Files.update(body,id, blob);
}
```


　`UrlFetchApp.fetch(imageURL).getBlob()`で指定したURLの画像を取得して、`Drive.Files.update(body,id, blob)`でファイルの更新をしてます。
上のフォトフレームのように、指定したフォルダ内のファイルの取得はフォルダIDを指定して

```
var files = DriveApp.getFolderById(id).getFiles();
while(files.hasNext()){
  file = files.next();
}
```


で行えて、更新日時が新しい順で取得されます。
またgetFilesByName(String)で指定した名前と一致するファイルを取得できます。


##Google Slidesを使って文字列や表を含む画像を生成する
APIから取得した情報の表示など、文字や図形を扱う場合はGoogleSlidesを利用します。
上記のカレンダーの場合、編集元として下の画像のような表を予め作成し、表にGASで値を代入しています。
![17.png](https://qiita-image-store.s3.amazonaws.com/0/176380/c0a6ed8a-4cca-bbc6-eee2-981b01d78346.png)

GASでGoogle Slidesの編集については他の方が解りやすく解説されてますのでここでは書きません。
またこの記事の最後にカレンダーのスクリプトのリンクを載せています。



###Google Slidesから画像を取得
VRC Panoramaで表示するには編集したスライドを画像に変換する必要があるので、APIを使ってサムネイルを取得します。

```
var response = Slides.Presentations.Pages.getThumbnail(presentationId, SlidesApp.openById(presentationId).getSlides()[0].getObjectId());
var blob = UrlFetchApp.fetch(response.contentUrl).getBlob();
```

　`Slides.Presentations.Pages.getThumbnail(presentationId,slideId)`にサムネイルを取得したいGoogle SlidesのファイルのIDとスライドのObjectIdを指定するとサムネイル画像の一時的なURLが生成され返されるので、`UrlFetchApp.fetch(url).getBlob()`でサムネイルを取得します。
　そして`Drive.Files.update(body,id, blob)`でVRC Panoramaで表示する画像を生成したものに書き換えて完了です。

##自動実行(cron)の設定
最後に、作成したスクリプトを指定した時間に起動させるには、ストップウォッチみたいなボタンをクリック
![18.png](https://qiita-image-store.s3.amazonaws.com/0/176380/15106303-a005-9812-1b3b-7f0d525fd95a.png)
すると起動トリガーの管理画面になるので、右下のトリガーを追加をクリックして、起動する時間の間隔などを設定して保存すればOKです。
![19.png](https://qiita-image-store.s3.amazonaws.com/0/176380/e83c8adc-ef54-723f-3446-b4e0a088d6a3.png)


#まとめ
GASはTwitterなど外部APIも使えるので、組み合わせたら面白いものが作れると思います。
  
他の皆さんのUnityやBlenderの記事の中、ほぼGASのことしか書いてないので場違い感ありますね・・・
記事を書くのはほぼ初めてで、大変なところもありましたが楽しかったです。ここまで読んでくれた方に感謝します。
 
 
#参考にしたページなど

+ [VRC Panorama用Googleカレンダーのイベント情報を取得してGoogleDrive上に画像として出力するスクリプト](https://harigami.net/contents?id=d74e7ac0-a43e-4bd6-8774-d58fa9bca08e)  
この記事の最初のカレンダーのスクリプトです。
+ [Google Apps ScriptでGoogle Driveのファイル一覧を取得する](https://www.gesource.jp/weblog/?p=8156)
+ [Google Apps Script Reference](https://developers.google.com/apps-script/reference/)

Google Slides関連

+ [[Google Apps Script]Google スライドでテキストボックスを追加し、文字装飾を行う](https://www.ka-net.org/blog/?p=10866)
+ [Google SlidesをGoogle Apps Scriptからいじる](https://qiita.com/chubflat/items/ed7c4ea8c8e9b9a7c2a6)
+ [【GAS】GoogleAppsScriptでGoogleSlidesのスライドを編集する](https://qiita.com/kado34/items/aa8a5edb9898e2002199)