Sketchfab Viewer API(JavaScript)で3Dコンテンツ操作のまとめ

こんにちは。フリーランス・コンサルタント&エンジニアの 九保すこひ です。

さてさて、最近3Dコンテンツの開発をさせていただきました!「Sketchfab」というサービスで実装したのですが、これがスグレモノで、

JavaScriptを使って3Dコンテンツを操作できる😊

ようになっています!

Sketchfabは以下のような3Dコンテンツの巨大サイトです。(2022年時点)

  • コミュニティメンバー:1,000万人
  • 3Dコンテンツ:500万点

引用:Sketchfab Celebrates 10 Million Members

サンプルを体験してみてください。
↓↓↓

出典:African penguin (Spheniscus demersus) Low poly by Major on Sketchfab

視点をグリグリ360°変更することができます。
すごいですね!

しかも、スマホでも操作できるので、次のような使われ方もしています。

  • 賃貸物件:ウェブ上で内覧
  • 商品販売:より詳しい質感を確かめられる
  • オーダーメイド:好みの色を指定して注文できる

そして、Sketchfabは「JavaScript API」を公開してくれています。

そこで❗

今回は「Sketchfab Viewer API」の基本的な操作をまとめてみました。
私のための備忘録ですが、何かの役に立ちましたら嬉しいです😊

ぜひ最後まで読んでくださいね!

「オクトパストラベラー、
絶対ラスボス倒せないでしょ😱」

【3Dコンテンツ】表示する基本

📝 実際のサンプルはこちら

基本の基本、Sketchfabで3Dコンテンツを表示させる(だけ)の部分です。
先にサンプルコードです。

<html>
<head>
    <title>Sketchfab Viewer API (JavaScript)基本操作サンプル</title>
</head>
<body>
    <div class="p-5 mx-auto md:w-1/2">
        <h1 class="text-lg mb-1">
            <span class="text-sky-700 font-bold">Sketchfab Viewer API (JavaScript)</span>:基本操作サンプル
        </h1>
        <iframe id="sketchfab-iframe" class="w-full" style="height:500px;"></iframe>
    </div>
    <script type="text/javascript" src="https://static.sketchfab.com/api/sketchfab-viewer-1.12.1.js"></script>
    <script src="https://cdn.tailwindcss.com/3.4.15"></script>
    <script>

        const iframe = document.getElementById('sketchfab-iframe');
        const version = '1.12.1';
        const uid = 'c599b3aa82eb46f7ba3bb2d22bd9dfc6'; // 3DモデルのUID
        const client = new Sketchfab(version, iframe);

        window.addEventListener('load', () => {

            client.init(uid, {
                success(api) {

                    api.start();

                    console.log('初期化に成功しました ^o^');

                },
                error() {

                    console.log('初期化に失敗しました..');

                }
            });

        });

    </script>
</body>
</html>

Sketchfab Viewer APIはライブラリを提供してくれているので、scriptタグを設置すれば簡単に3Dコンテンツを表示することができます。

もしnpmでインストールしたい場合は、

npm i @sketchfab/viewer-api

でパッケージをインストールして、次のように呼び出します(必要ならビルドしてください)

import Sketchfab from '@sketchfab/viewer-api';
window.Sketchfab = Sketchfab;

なお、コード中にある「uid」は3DコンテンツのIDです。

const uid = 'c599b3aa82eb46f7ba3bb2d22bd9dfc6';

別の3Dコンテンツを表示したい場合は、Sketchfabの3Dモデルページの各URLから取得してください。

たとえば、以下の場合、最後の32文字の英数字部分です。(※文字数は変わるかもしれません)

https://sketchfab.com/3d-models/african-penguin-spheniscus-demersus-low-poly-9e59070815fe451d93398e2ebdb9bb92

【3Dコンテンツ】クリックイベントをつくる

📝 実際のサンプルはこちら

3Dコンテンツがクリックされた「構成パーツ」の情報を取得するコードをご紹介します。

<html>
<head>
    <title>Sketchfab Viewer API (JavaScript)基本操作サンプル</title>
</head>
<body>
    <div class="p-5 mx-auto md:w-1/2">
        <h1 class="text-lg mb-1">
            <span class="text-sky-700 font-bold">Sketchfab Viewer API (JavaScript)</span>:基本操作サンプル
        </h1>
        <iframe id="sketchfab-iframe" class="w-full" style="height:500px;"></iframe>
    </div>
    <script type="text/javascript" src="https://static.sketchfab.com/api/sketchfab-viewer-1.12.1.js"></script>
    <script src="https://cdn.tailwindcss.com/3.4.15"></script>
    <script>

        const iframe = document.getElementById('sketchfab-iframe');
        const version = '1.12.1';
        const uid = 'c599b3aa82eb46f7ba3bb2d22bd9dfc6'; // 3DモデルのUID
        const client = new Sketchfab(version, iframe);

        window.addEventListener('load', () => {

            client.init(uid, {
                success(api) {

                    api.start();
                    api.addEventListener('viewerready', () => { // 初期化が完了したとき

                        // クリックイベント
                        api.addEventListener('click', (info) => {

                            console.log(info); // クリックされたノード(構成パーツ)のデータ

                        });

                    });

                },
                error() {

                    console.log('初期化に失敗しました..');

                }
            });

        });

    </script>
</body>
</html>

Sketchfabが初期化できた時点で、JavaScriptのようにイベントをセットすればOKです。

api.addEventListener('click', (info) => {

    // クリックしたらここが実行される

});

【3Dコンテンツ】色を変える

📝 実際のサンプルはこちら

次にクリックした構成パーツの色を変えてみましょう。
サンプルソースです。

<html>
<head>
    <title>Sketchfab Viewer API (JavaScript)基本操作サンプル</title>
</head>
<body>
    <div class="p-5 mx-auto md:w-1/2">
        <h1 class="text-lg mb-1">
            <span class="text-sky-700 font-bold">Sketchfab Viewer API (JavaScript)</span>:基本操作サンプル
        </h1>
        <iframe id="sketchfab-iframe" class="w-full" style="height:500px;"></iframe>
    </div>
    <script type="text/javascript" src="https://static.sketchfab.com/api/sketchfab-viewer-1.12.1.js"></script>
    <script src="https://cdn.tailwindcss.com/3.4.15"></script>
    <script>

        const iframe = document.getElementById('sketchfab-iframe');
        const version = '1.12.1';
        const uid = 'c599b3aa82eb46f7ba3bb2d22bd9dfc6'; // 3DモデルのUID
        const client = new Sketchfab(version, iframe);

        // データ
        const colors = [
            [0.5, 0.1, 0.1], // 赤
            [0.1, 0.5, 0.1], // 緑
            [0.1, 0.1, 0.5], // 青
            [0.5, 0.5, 0.0], // 黄色
            [0.4, 0.1, 0.4], // 紫
            [0.0, 0.5, 0.5], // 水色
        ];
        let colorIndex = 0;

        window.addEventListener('load', () => {

            client.init(uid, {
                success(api) {

                    api.start();
                    api.addEventListener('viewerready', () => { // 初期化が完了したとき

                        // クリックイベント
                        api.addEventListener('click', (info) => {

                            if(info.material) {

                                const material = info.material;

                                // 新しいデータをセット
                                material.channels.AlbedoPBR.color = colors[colorIndex];;

                                // データを更新
                                api.setMaterial(material);

                                // 次の色インデックスに更新
                                colorIndex = (colorIndex + 1) % colors.length;

                            }

                        });

                    });

                },
                error() {

                    console.log('初期化に失敗しました..');

                }
            });

        });

    </script>
</body>
</html>

やることは、クリックした構成パーツのmaterialデータ(オブジェクト)の中身を変更してsetMaterial()にセットするだけです。

気をつけないといけないのが、色データは16進数(例:#cccccc)ではなく、[R, G, B]の配列で指定しないといけない点です。

なお、3Dデータにより違うようですが、もしこのコードで色が変わらない場合は以下のようなパラメータを変更してみてください。

  • AlbedoPBR
  • DiffusePBR
  • EmitColor

その他のパラメータ一覧は、こちらのページのMaterial channelsを参照してください。

また、パラメータが有効になってるかどうかは、enabled部分がどうなっているか(trueかfalse)で判断してください。

他のパラメータを変更することで、色だけでなく光沢や透過率も変更することができます。

【3Dコンテンツ】表示/非表示にする

📝 実際のサンプルはこちら

次はコンテンツの表示/非表示です。
サンプルソースはこちら。

<html>
<head>
    <title>Sketchfab Viewer API (JavaScript)基本操作サンプル</title>
</head>
<body>
    <div class="p-5 mx-auto md:w-1/2">
        <h1 class="text-lg mb-1">
            <span class="text-sky-700 font-bold">Sketchfab Viewer API (JavaScript)</span>:基本操作サンプル
        </h1>
        <iframe id="sketchfab-iframe" class="w-full" style="height:500px;"></iframe>
    </div>
    <script type="text/javascript" src="https://static.sketchfab.com/api/sketchfab-viewer-1.12.1.js"></script>
    <script src="https://cdn.tailwindcss.com/3.4.15"></script>
    <script>

        const iframe = document.getElementById('sketchfab-iframe');
        const version = '1.12.1';
        const uid = 'c599b3aa82eb46f7ba3bb2d22bd9dfc6'; // 3DモデルのUID
        const client = new Sketchfab(version, iframe);

        window.addEventListener('load', () => {

            client.init(uid, {
                success(api) {

                    api.start();
                    api.addEventListener('viewerready', () => { // 初期化が完了したとき

                        // クリックイベント
                        api.addEventListener('click', (info) => {

                            const instanceId = info.instanceID;

                            if(instanceId) {

                                api.hide(instanceId, (err) => { // パーツを非表示

                                    if (! err) {

                                        console.log('非表示にした構成パーツ:', instanceId);

                                    }

                                    // 3秒後:非表示したパーツを表示
                                    setTimeout(() => {

                                        api.show(instanceId, (err) => { // パーツを表示

                                            if (! err) {

                                                console.log('表示にした構成パーツ:', instanceId);

                                            }

                                        });

                                    }, 1000);

                                });

                            }

                        });

                    });

                },
                error() {

                    console.log('初期化に失敗しました..');

                }
            });

        });

    </script>
</body>
</html>

【3Dコンテンツ】カメラ視点を変更する

📝 実際のサンプルはこちら

続いては、カメラの視点(ポジション)を変更したり、逆に現在の位置情報を取得する方法です。

ソースコードはこちら。

<html>
<head>
    <title>Sketchfab Viewer API (JavaScript):カメラ視点の変更</title>
</head>
<body>
    <div class="p-5 mx-auto md:w-1/2">
        <h1 class="text-lg mb-1">
            <span class="text-sky-700 font-bold">Sketchfab Viewer API (JavaScript)</span>:カメラ視点の変更
        </h1>
        <iframe id="sketchfab-iframe" class="w-full" style="height:500px;"></iframe>
        <div class="text-center mt-3">
            <button id="camera-button-front" class="bg-sky-600 text-white px-4 py-2 rounded">前から</button>
            <button id="camera-button-rear" class="bg-sky-600 text-white px-4 py-2 rounded">後ろから</button>
            <button id="camera-button-top" class="bg-sky-600 text-white px-4 py-2 rounded">上から</button>
            <button id="camera-button-bottom" class="bg-sky-600 text-white px-4 py-2 rounded">下から</button>
        </div>
        <div class="text-center mt-3">
            <button id="camera-position" class="bg-sky-600 text-white px-4 py-2 rounded">カメラ位置の取得</button>
        </div>
    </div>
    <script type="text/javascript" src="https://static.sketchfab.com/api/sketchfab-viewer-1.12.1.js"></script>
    <script src="https://cdn.tailwindcss.com/3.4.15"></script>
    <script>

        const iframe = document.getElementById('sketchfab-iframe');
        const version = '1.12.1';
        const uid = 'c599b3aa82eb46f7ba3bb2d22bd9dfc6'; // 3DモデルのUID
        const client = new Sketchfab(version, iframe);

        const positionItems = [
            {
                key: 'front',
                position: [0.00027227842457719196, -0.12323447965269245, 0.006010688798040832],
                target: [0.0002722784245772618, -1.2963339716016102e-18, 0.006010688798040856],
            },
            {
                key: 'rear',
                position: [0.0017653025285150942, 0.12322533725599279, 0.005855406984030233],
                target: [0.0002722784245772618, -1.2963339716016102e-18, 0.006010688798040856],
            },
            {
                key: 'top',
                position: [0.00021956383795308866, -0.0430367330509624, 0.2757288099404258],
                target: [0.0002722784245772618, -1.2963339716016102e-18, 0.006010688798040856],
            },
            {
                key: 'bottom',
                position: [0.0002911564848656767, -0.004290098937768513, -0.26708567283614254],
                target: [0.0002722784245772618, -1.2963339716016102e-18, 0.006010688798040856],
            },
        ];

        window.addEventListener('load', () => {

            client.init(uid, {
                success(api) {

                    api.start();
                    api.addEventListener('viewerready', () => { // 初期化が完了したとき

                        // カメラ位置の変更
                        for(const key in positionItems) {

                            const positionItem = positionItems[key];
                            const button = document.getElementById(`camera-button-${positionItem.key}`);
                            button.addEventListener('click', () => {

                                const position = positionItem.position;
                                const target = positionItem.target;
                                const duration = 1; // 移動時間(秒)
                                api.setCameraLookAt(position, target, duration, (err) => {

                                    if (! err) {

                                        console.log('カメラ視点を変更しました:', positionItem);

                                    }

                                });

                            });

                        }

                        // カメラ位置の取得
                        const positionButton = document.getElementById('camera-position');
                        positionButton.addEventListener('click', () => {

                            api.getCameraLookAt(function(err, camera) {

                                if(! err) {

                                    console.log('ポジション:', camera.position);
                                    console.log('ターゲット:', camera.target);

                                }

                            });

                        });

                    });

                },
                error() {

                    console.log('初期化に失敗しました..');

                }
            });

        });

    </script>
</body>
</html>

カメラ位置の変更は、先にデータを用意しておいて、setCameraLookAt()を実行するだけでOKです。

逆に今表示している3Dコンテンツの位置情報を取得する場合はgetCameraLookAt()です。

【3Dコンテンツ】背景色を変更する

📝 実際のサンプルはこちら

今回で言うと車ではなく、その背景の色を変更してみます。
ソースコードはこちら。

<html>
<head>
    <title>Sketchfab Viewer API (JavaScript):背景色の変更</title>
</head>
<body>
    <div class="p-5 mx-auto md:w-1/2">
        <h1 class="text-lg mb-1">
            <span class="text-sky-700 font-bold">Sketchfab Viewer API (JavaScript)</span>:背景色の変更
        </h1>
        <iframe id="sketchfab-iframe" class="w-full" style="height:500px;"></iframe>
        <div class="text-center mt-3">
            <button id="background-button" class="bg-sky-600 text-white px-4 py-2 rounded">背景色を変更する</button>
        </div>
    </div>
    <script type="text/javascript" src="https://static.sketchfab.com/api/sketchfab-viewer-1.12.1.js"></script>
    <script src="https://cdn.tailwindcss.com/3.4.15"></script>
    <script>

        const iframe = document.getElementById('sketchfab-iframe');
        const version = '1.12.1';
        const uid = 'c599b3aa82eb46f7ba3bb2d22bd9dfc6'; // 3DモデルのUID
        const client = new Sketchfab(version, iframe);

        // データ
        const colors = [
            [0.5, 0.1, 0.1], // 赤
            [0.1, 0.5, 0.1], // 緑
            [0.1, 0.1, 0.5], // 青
            [0.5, 0.5, 0.0], // 黄色
            [0.4, 0.1, 0.4], // 紫
            [0.0, 0.5, 0.5], // 水色
        ];
        let colorIndex = 0;

        window.addEventListener('load', () => {

            client.init(uid, {
                success(api) {

                    api.start();

                    const button = document.getElementById('background-button');
                    button.addEventListener('click', () => {

                        const color = colors[colorIndex];

                        api.setBackground({color: color}, () => {

                            console.log('変更した背景色:', color);

                        });

                        colorIndex = (colorIndex + 1) % colors.length;

                    });

                },
                error() {

                    console.log('初期化に失敗しました..');

                }
            });

        });

    </script>
</body>
</html>

背景色を変更するにはsetBackground()を呼ぶだけでOKです。

なお、色ではなく画像をセットすることもできるようですが、以下のようにUIDで指定しないといけません。

api.setBackground({uid: '51af6a870cce449eb75b0345feebaebb'}, () => {

    //

});

つまり、3Dコンテンツの中に同梱している必要がなります。

【3Dコンテンツ】スクリーンショットでダウンロードする

📝 実際のサンプルはこちら

好きな位置で3Dコンテンツを表示し、そのスクリーンショットをとる方法です
ソースコードはこちら。

<html>
<head>
    <title>Sketchfab Viewer API (JavaScript):スクリーンショットの保存</title>
</head>
<body>
    <div class="p-5 mx-auto md:w-1/2">
        <h1 class="text-lg mb-1">
            <span class="text-sky-700 font-bold">Sketchfab Viewer API (JavaScript)</span>:スクリーンショットの保存
        </h1>
        <iframe id="sketchfab-iframe" class="w-full" style="height:500px;"></iframe>
        <div class="text-center mt-3">
            <button id="screenshot-button" class="bg-sky-600 text-white px-4 py-2 rounded">スクリーンショットを保存する</button>
        </div>
    </div>
    <script type="text/javascript" src="https://static.sketchfab.com/api/sketchfab-viewer-1.12.1.js"></script>
    <script src="https://cdn.tailwindcss.com/3.4.15"></script>
    <script>

        const iframe = document.getElementById('sketchfab-iframe');
        const version = '1.12.1';
        const uid = 'c599b3aa82eb46f7ba3bb2d22bd9dfc6'; // 3DモデルのUID
        const client = new Sketchfab(version, iframe);

        window.addEventListener('load', () => {

            client.init(uid, {
                success(api) {

                    api.start();

                    const button = document.getElementById('screenshot-button');
                    button.addEventListener('click', () => {

                        api.getScreenShot('image/png', (err, base64String) => {

                            if (! err) {

                                const fileName = `screenshot-${Date.now()}.png`;
                                const downloadLink = document.createElement('a');
                                document.body.appendChild(downloadLink);

                                downloadLink.href = base64String;
                                downloadLink.target = '_self';
                                downloadLink.download = fileName;
                                downloadLink.click();

                            }

                        });

                    });

                },
                error() {

                    console.log('初期化に失敗しました..');

                }
            });

        });

    </script>
</body>
</html>

注意が必要なのが、データはbase64形式(文字列)として取得される点です。

今回のコードのようにリンクの移動先としてセットすれば、データの変換は不要です。

企業様へのご提案

Sketchfabを使うと、ウェブ上で3Dコンテンツを提供できるようになります。

つまり、店舗に行かなくても実物を想像しやすい販売ができるわけです。

繰り返しになりますが、冒頭部分で紹介した以下3つのような活用をすることで、り来店時に近い形でのセールスにつなげてはいかがでしょうか。

  • 賃貸物件:ウェブ上で内覧
  • 商品販売:より詳しい質感を確かめられる
  • オーダーメイド:好みの色を指定して注文できる

もしこういった機能をご希望でしたら、ぜひお問い合わせから無料相談してくだい。

お待ちしております😊

おわりに

ということで、今回は久しぶりにブログ記事を書きました!

以前は「毎週書かなきゃダメ!」という制約があり、細部が荒くなることもありましたが、不定期となるとじっくり記事を書けるので、これもメリットだなと感じています。

それにしても、ブログ記事ってひとつ書くだけでも、なかなか労力がいりますね。自分でもよく毎週投稿なんてやってたなってカンジです(笑)

その分スキルアップを実感できているので、ぜひ皆さんもやってみてくださいね😊

ではでは〜!

「チョコボールの銀エンゼルが連続で出たら、
そんなに欲しくなくても次買っちゃうね(笑)」

このエントリーをはてなブックマークに追加       follow us in feedly  
開発のご依頼お待ちしております
開発のご依頼はこちらから: お問い合わせ
どうぞよろしくお願いいたします! by 九保すこひ