![見出し画像](https://assets.st-note.com/production/uploads/images/153050110/rectangle_large_type_2_932d0be70cedfbe47c86cfd5af34010b.jpeg?width=1200)
【GAS】画像や3Dデータでメタバースの様なバーチャル展覧会を開いてみよう〔解説2〕A-Frameの立体要素にGドライブ内の画像や3Dデータを反映する
Googleの無料サービスである、GAS(Google Apps Script)を使って、画像や3Dデータを配置した仮想空間を作り、かんたんなバーチャル展覧会を開く記事を以下でご紹介しました。
先回の記事では、GASのテンプレートにJSライブラリ「A-Frame」を導入すると、専用のタグを使って3Dシーンや3D要素をHTML文書内に配置できることをご説明しました。
今回の記事では、配置した3D要素上に、画像や3Dデータを表示させる方法についてご紹介します。
A-Fremeで生成された3Dパネルに画像をマッピングする
A-Frameは無料のJSライブラリで、導入することにより、HTML文書内で、タグ付きコードで3D空間を作り、その中に3D要素を配置できるようになります。
例えば、<a-plane>タグを使うと、3Dパネルが配置できます。
大きさ、配置する位置、向きなどについては、以下の例の様に、タグ内に各属性値を記述して指定します。(コードは説明のため、やや単純化しています)
<a-plane
id="ID名"
width="巾"
height="高さ"
position="座標"
rotation="角度" >
</a-plane>
A-Frameでは、3Dパネルこうして配置した立体に、画像をマッピングしたり立体データを紐付けすることができます。立てて配置した3Dパネルに画像データをマッピングすると、額縁に掲げた絵画の様になり、バーチャル展覧会が表現できるという訳です。
画像データはURLでファイルを指定して行うが・・・
A-Frameでマッピングを実装するのは非常に簡単で、サーバ内に保存した画像(JPG)ファイルのリンクを「src」属性にセットすれば完了します。
コードとしては、以下の様になります。
<a-plane
src="HTTPS://・・・・画像.jpg" >
</a-plane>
非常に簡単なコードですが、残念ながら、GASのテンプレートでこのコードを使うには問題があります。
前述のコードをテンプレート内で記述すると、多くの場合、リンク切れの現象が生じてしまうのです。
src="HTTPS://・・・・画像.jpg"
上記の様なコードで引用先のデータを指定しても、デプロイして実行すると、しばしばデータを取得できずに下記の様なグレイ表示となってしまいます。
![](https://assets.st-note.com/img/1725376360-4R8qSYaAx5k2WUFwzQt3d6nC.png)
恐らく、リンク先からデータを読み込まないうちに、ブラウザにレスポンスされてしまうためだと思いますが、これでは使えませんね。
リンク情報を使わずに画像データを引用する方法はないものでしょうか?
ファイルのバイナリデータをBASE64エンコードで文字列に変換して代入する
一つの解決方法が、画像ファイルのリンクを用いてデータをセットする代わりに、画像ファイルのデータを直接src属性にセットすることです。
とはいえ、画像ファイルのバイナリデータ(0と1のデジタル情報)を直接コード中で扱うのは簡単ではありません。
こうした場合に有用なのが、ファイルのバイナリデータをBASE64エンコードという方法でまるごと文字列に変換して、これを利用する方法です。
文字列に変換された画像ファイルのデータは、以下のコードによりマッピングに使える様になります。
<a-plane
src=”data:image/png;base64、文字列” >
</a-plane>
この方法を使うと、動作は遅いのですが、テンプレート内でも確実に画像データを引用することができます。
![](https://assets.st-note.com/img/1725376302-RTWiZvLQotxUDd9b2GBmay5O.png?width=1200)
BASE64エンコードとは
BASE64エンコードとは、0と1のビットデータを、6ビット単位で区切り、区切りごとに1つの半角文字に置き換えるコード変換方法です。
0111010111111・・・・
⇒ 011101 011111 1・・・・
⇒ A b 5 ・・・(コードは適当です)
6ビットは情報量としては「2の6乗」=64通りの情報が識別に必要となりますが、これを64種類の文字で対応させるというわけです。
デジタルデータは、4ビット、8ビット、16ビットいう、互いに情報量が2倍または半分となる単位でエンコードすることが多いのですが、6ビットという区切り方をするのは、こうすることで、半角文字のほぼ全種類を無駄なく利用でき、エンコード後の文字列サイズが少なくなるからです。
変換すると、バイナリデータを一般の文字列変数として扱えるため、プログラムでの扱いが非常に平易になります。
Googleドライブに保存した画像ファイルをBASE64エンコードして取り込む
A-Frameをテンプレート内で記述して3D要素を表現し、ここに画像データをマッピングするには、ファイルを文字列にエンコードして利用すると良いことは判りました。
では、画像ファイルのデータを、どうすれば文字列にエンコードできるのでしょうか。
Googleドライブ内のファイルを、スクリプト関数を使ってBASE64エンコードする
Googleスクリプトには、base64Encode( )という関数が用意されています。この関数を使えば、Googleドライブ内のファイルを簡単にエンコードできます。
コードの概要を以下に示します。
//Gドライブ内のファイルをファイルIDで取得
ファイル = DriveApp.getFileById(ファイルID);
//ファイルのバイナリデータを取得
バイナリデータ = ファイル.getBlob().getBytes();
//BASE64エンコードで文字列に変換
文字列 = Utilities.base64Encode(バイナリデータ);
注意)上記はテンプレートではなく、スクリプト内に記述するコードです。
上記の一連の処理を、ファイルIDを引数、エンコード結果を返り値とした関数にしておきます。
★スクリプト内のコードです★
function Base64エンコード(ファイルID){
//Gドライブ内のファイルをファイルIDで取得
ファイル = DriveApp.getFileById(ファイルID);
//ファイルのバイナリデータを取得
バイナリデータ = ファイル.getBlob().getBytes();
//BASE64エンコードで文字列に変換
文字列 = Utilities.base64Encode(バイナリデータ);
returen 文字列;
}
テンプレートからスクリプト内の関数をgoogle.script.run関数で遠隔作動させて、返り値を受け取る
さて、上記のコードはあくまでスクリプト内での関数なので、テンプレート内では利用できません。
テンプレートは、ユーザのブラウザ内でWEBページとして作動するもので、スクリプトはGドライブ内で作動するものですので、両者の連携は一見困難です。これにどうやって対処すべきでしょうか?
両者の連携を可能にするために、GASのテンプレートには、google.script.run 関数が用意されています。
この関数は、テンプレート(WEBページ)側からスクリプト内の関数の遠隔操作を実現する関数で、テンプレートの<script>セクション内で、子関数にスクリプト内の関数を指定して使います。
★テンプレート内のコードです★
<script>
・・・・
google.script.run
//実行するスクリプト内の関数を、子関数として指定
.Base64エンコード(ファイルID);
・・・・
</script>
google.script.run関数は、一般のHTML文章やJavaScriptでは定義されていない、GASのテンプレート内でだけ使える関数です。
そして、返り値を受け取ったら行う処理を、.withSuccessHandler()という子要素を追加して、以下の様に記述しておきます。
★テンプレート内のコードです★
<script>
・・・・
google.script.run
//↓↓↓↓ ★返り値resの取得に成功した場合の処理★ ↓↓↓
.withSuccessHandler(res => {
・・・resを使った処理を記述・・・
}
//↑↑↑↑ ★返り値resの取得に成功した場合の処理★ ↑↑↑
//実行するスクリプト内の関数を、子関数として指定
.Base64エンコード(ファイルID);
・・・・
</script>
この一連の処理をイメージ図にすると、以下の様になります。
![](https://assets.st-note.com/img/1725661122-ISGoBJtmE16qra7ReYkP8AZH.png)
3Dパネルに、画像ファイルのデータ(文字列にエンコードされています)をセットするコードは、setAttribute()というJava Scriptの関数を使って、以下の様に記述します。
.withSuccessHandler(res => {
//作成済みの3D要素を取得
3Dパネル = document.getElementById(要素のID名);
//BASE64エンコードされた文字列(res)を"src"属性にセット
3Dパネル.setAttribute("src", "data:image/png;base64," + res);
}
こうして、見事、画像ファイルのデータが、A-Frameで生成した3D図名にマッピングされます。
データが3D図形(GLTFファイル)の場合のコード
バーチャル展示会で展示する彫刻は、JPGファイルではなく、GLTFファイルを使います。
この場合は、まず、A-Frameで、<a-gltf-model >タグを使って、以下の様に記述します。
<a-gltf-model
id="3D図形"
dynamic-body="shape: sphere; mass: 1"
position="座標">
</a-gltf-model>
ここに、先の画像と全く同様のコードで、エンコードしたGLTFファイルの文字列をセットします。違いは、データ種をあらわず部分が、「data:image/png」から、「data:gltf-model/glb」と変わっているだけです。
.withSuccessHandler(res => {
//作成済みの3D要素を取得
3D要素 = document.getElementById(3D図形);
//BASE64エンコードされた文字列(res)を"src"属性にセット
3D要素.setAttribute("src", "data:gltf-model/glb," + res);
}
こうして、A-Frameで生成したバーチャル立体図形に、Gドライブ内の画像や3D図形のファイル情報を紐付けられました。
![](https://assets.st-note.com/img/1725661667-LEZC3NYKrbAIcm6THVJn80uk.png?width=1200)
GASの「テンプレート」には、一般のHTMLファイルにない機能がある
テンプレートは、GASでWEBページを表示させる際に、HTML文書やJavaScriptを記載するためのプラットフォームですが、単なるコード記載場所ではなく、それ以上の機能を有しています。
とりわけ、さきほどご紹介した様な、Googleドライブと動的に連携するための機能が盛り込まれている点が秀逸な点です。これを利用すれば、アマチュアでも比較的容易にWEBアプリを作ることができます。
Google.Script.run関数はブラウザのAJAX(非同期通信)機能を簡単に扱える様にしたもの
今日、WEBアプリは、日常さまざまなシーンで利用されていますが、その機能の鍵となる部分は、ユーザ側(クライアント/ブラウザ側)と、サーバ側とのデータ通信です。
通信方式のなかで、良く利用されているのが、AJAX(非同期通信)という機能です。これは、ユーザ側からデータの要求があった際、タイムラグがあっても処理がスムーズに進む様、通信が成功したデータから順次処理されるというものです。
アマチュアがその機能を使いこなすのは、容易ではありませんが、GASでは、簡単な関数によってアマチュアでもこの機能を使える様になっています。
GASは、Googleアプリのマクロとして知られていますが、もうひとつ、こうしたWEBアプリを作る手軽な機能を有している、というのは、他のマクロ言語にはない特長です。
次の記事では、GASのコードの全体についてご説明します。
![](https://assets.st-note.com/img/1725548454-HSVoYbPiyksZtxNGlK2CLrw9.png)