ホーム 記事一覧 ブック DH週間トピックス 検索 このサイトについて
English
Sketchfab APIでGLBファイルをダウンロード・表示するWebアプリを作る

Sketchfab APIでGLBファイルをダウンロード・表示するWebアプリを作る

Sketchfab APIを使って3DモデルをGLBファイルとしてダウンロードし、ブラウザ上でThree.jsで表示するWebアプリを作成しました。本記事では、セキュリティを考慮したアーキテクチャ設計から実装まで解説します。 やりたかったこと Sketchfab上の3DモデルをGLB形式でダウンロードしたい ダウンロードしたGLBをブラウザ上で3D表示したい APIトークンを安全に管理したい 技術スタック Next.js 16(App Router) React Three Fiber / @react-three/drei TypeScript 最初に試したこと:クライアントサイドのみで実装 最初はシンプルにHTML + JavaScriptだけで実装しようとしました。 // Sketchfab APIからダウンロードURLを取得 const response = await fetch( `https://api.sketchfab.com/v3/models/${modelUid}/download`, { headers: { 'Authorization': `Token ${apiToken}` } } ); const data = await response.json(); console.log(data.glb.url); // 署名付きS3 URL これ自体は動作しましたが、2つの問題がありました。 問題1: APIトークンの露出 クライアントサイドでAPIトークンを使用すると、ブラウザの開発者ツールから簡単に確認できてしまいます。APIトークンが漏洩すると、他人があなたのアカウントでAPIを利用できてしまうため、これは避けるべきです。 問題2: CORSエラー(場合による) ブラウザのセキュリティ制限により、異なるオリジンへのリクエストが制限されることがあります。今回のケースでは、Sketchfab APIへのリクエスト自体はCORSが許可されていましたが、環境によっては問題になる可能性があります。 解決策:サーバーサイドAPIを経由する設計 Next.jsのAPI Routesを使って、サーバーサイドでSketchfab APIと通信する設計にしました。 ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ │ │ │ │ │ │ Client │────▶│ Next.js API │────▶│ Sketchfab API │ │ (Browser) │ │ (Server) │ │ │ │ │◀────│ │◀────│ │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ │ ┌─────────────────┐ │ │ │ └──────────▶│ S3 (GLB) │ │ 署名付きURL │ └─────────────────┘ ポイント:署名付きURLの活用 Sketchfab APIは、GLBファイルの実体ではなく「署名付きS3 URL」を返します。 ...

Sketchfabのアノテーションを試す

Sketchfabのアノテーションを試す

概要 Sketchfabのアノテーションを試してみましたので、備忘録です。 最終的に、以下のようなビューアを作成しました。 https://nakamura196.github.io/SketchfabAnnotationViewer/ https://youtu.be/iEe6TbI3X70 使用データ 「菊池市/デジタルアーカイブ」の「石淵家地球儀」を対象とします。 https://adeac.jp/kikuchi-city/catalog/e0001 使用例 まずSketchfabに3Dデータをアップロードしました。 https://skfb.ly/pt8oU そしてアノテーションを付与しました。結果、以下のようなページが用意されました。 APIを利用する 以下のリポジトリも参考にしてください。 https://github.com/nakamura196/SketchfabAnnotationViewer 以下のようなスクリプトにより、アノテーションの一覧取得や、初期表示に使用するアノテーションの指定、選択したアノテーションへのフォーカスなどを行うことができました。 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Sketchfab Annotation Viewer</title> <script src="https://cdn.tailwindcss.com"></script> </head> <body class="bg-gray-100 font-sans"> <!-- メインコンテナ --> <div class="max-w-4xl mx-auto py-10 px-4"> <!-- ヘッダー --> <h1 class="text-2xl font-bold text-gray-800 text-center mb-6"> Sketchfab Annotation Viewer </h1> <!-- 3Dビューア --> <div class="mb-6"> <iframe id="api-frame" width="100%" height="480" class="rounded shadow-md border border-gray-300" src="" allowfullscreen ></iframe> </div> <!-- アノテーションリスト --> <h2 class="text-xl font-semibold text-gray-700 mb-4">Annotations</h2> <ul id="annotation-list" class="space-y-2"> <!-- アノテーション項目はJavaScriptで追加 --> </ul> </div> <script src="https://static.sketchfab.com/api/sketchfab-viewer-1.12.1.js"></script> <script src="script.js"></script> </body> </html> // Sketchfab Viewerを埋め込むためのiframeを取得 const iframe = document.getElementById('api-frame'); const client = new Sketchfab(iframe); const urlParams = new URLSearchParams(window.location.search); // SketchfabモデルIDを指定 const modelId = urlParams.get('id') || '02add905e79c446994f971cbcf443815'; // 'id'パラメータを取得 const pos = parseInt(urlParams.get('pos'), 10) || 0; // APIのオプションを指定してモデルをロード client.init(modelId, { success: function (api) { api.start(); api.addEventListener('viewerready', function () { setupAnnotations(api); focusAnnotation(api, pos); // 最初のアノテーションにフォーカス }); }, error: function () { console.error('Sketchfab Viewer failed to load'); }, }); function setupAnnotations(api) { api.getAnnotationList(function (err, annotations) { if (err) { console.error('Failed to fetch annotations'); return; } // アノテーション一覧をHTMLに追加 const annotationListContainer = document.getElementById('annotation-list'); annotations.forEach((annotation, index) => { const annotationItem = document.createElement('li'); annotationItem.textContent = annotation.name; // アノテーションタイトル annotationItem.addEventListener('click', () => { focusAnnotation(api, index); // クリック時にフォーカス }); annotationListContainer.appendChild(annotationItem); }); }); } function focusAnnotation(api, annotationIndex) { api.gotoAnnotation(annotationIndex, { preventCameraAnimation: false, // アニメーションを許可 }); // api.showAnnotation(annotationIndex); // アノテーションを表示 // api.showAnnotationTooltip(annotationIndex); // アノテーションツールチップを表示 } まとめ 3Dデータへのアノテーションの応用にあたり、参考になりましたら幸いです。 ...