A-Frameで日本語を表示(スクリプトで実装)


はじめに

はじめまして、最近A-Frameがマイブームです。
むちゃくちゃ簡単に3D、VRが出来ることに感動するのですが、
如何せん日本語の表示が未対応なのがつらいところです。

現状は2つほど表示する方法がありますが、どちらも十全ではないので、
別の方法をjavascriptで実装してみました。

既存の方法

既存の方法は以下の2つとその欠点

  • フォントデータを変換して使う
    • 欠点:あらかじめ使用する文字すべてを準備する必要がある。
  • HTML Shaderを使う
    • 欠点:透過できない。htmlのbackgroundを透明にすると、3D空間ではなくcanvasを透過してしまう。(demo参照)

別の方法

ざっくりした方法
1. 対象の日本語テキストを生成したcanvasに描画
2. canvas情報をbase64に変換
3. src=base64のa-imageを挿入

コード

今回の方法と、参考にHTMLShaderを使った方法を実装
ざっくり実装なのでいろいろ適当


<html>
<head>
    <meta charset="utf-8"/>
    <title>aframeMultiByte</title>
    <script src="https://aframe.io/releases/1.0.4/aframe.min.js"></script>
    <script src="./js/aframe-html-shader.min.js"></script>
    <script src="./js/html2canvas.min.js"></script>
    <style>
        .target{
            width:500px;
            height:100px;
            font-size:20pt;
            background:rgba(0,0,0,0);
        }
    </style>
</head>
<body>
    <div id="target1" class="target">
        <p>.こんにちは世界(HTML Shader)🌝</p>
    </div>
    <a-scene vr-mode-ui="enabled: true" style="position:fixed;top:0;">
        <a-box position="-1 0.5 -3" rotation="0 45 0" color="#4CC3D9"></a-box>
        <a-sphere position="0 1.25 -5" radius="1.25" color="#EF2D5E"></a-sphere>
        <a-cylinder position="1 0.75 -3" radius="0.5" height="1.5" color="#FFC65D"></a-cylinder>
        <a-plane position="0 0 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4"></a-plane>
        <a-sky color="#ECECEC"></a-sky>

        <a-plane position="-1.5 2 -1" width="2" height="0.5" material="shader:html;target: #target1;"></a-plane>

        <a-entity mb-text position="1.5 1.5 -1" data-text="新.こんにちは世界(script)🌝"></a-entity>
      </a-scene>
</body>
<script>
function aframeMutlByte(){
    document.querySelectorAll('[mb-text]:empty').forEach(mb_text=>{
        console.log(mb_text.dataset.text)
        const text  =mb_text.dataset.text
        const text_cnt = text.length
        const width = text_cnt*1.4
        const height= 1.6
        let cvs = document.createElement('canvas')
        let ctx = cvs.getContext('2d')
        cvs.width = width*100
        cvs.height = height*100
        ctx.fillStyle = "rgb(0, 0, 0)"
        ctx.font = '100pt Arial'
        ctx.fillText(text,0,125)

        const base64 = cvs.toDataURL("image/png")
        mb_text.innerHTML=`<a-image scale="${(width)/10} ${height/10} 1" src="${base64}"></a-image>`
    })
}
    aframeMutlByte()
</script>
</html>

結果

demo

日本語だけでなく顔文字も透過した状態で表示される。

最後に

作りこめば、フォントの指定とか、改行とかオプションをいろいろ実装できそう。
ざっくり作ったので、VR端末での動作確認などは要検証

追記(2020-07-18)

VRモードの設定つけ忘れてたのでコード修正
一応Android9のChrome、iOS13のsafari、OculusQuestで大丈夫だったので、
おおよそ使えそう。

参考サイト

A-Frame: Hello WebVR
A-Frameで日本語を表示したい
A-FrameとHTML Shaderで美しい日本語テキストを表示する方法