Matterport SDK 2021 Tutorial (English)
まず、Matterport アプリのディレクトリを作成します:
mkdir matterport-test
cd matterport-test
次に、簡単なWebサーバーを設定することから始めましょう ...
ウェブサーバー
__Node.js__で__Express__ウェブサーバーを使用してページを提供します。
Expressのインストール
まず、空のプロジェクトの「package.json」ファイルを初期化しましょう:
npm init -y
次に、Express の最新の安定版をインストールします:
npm install express
ウェブサーバーの作成
まず、ウェブサーバー用のJavaScriptファイルを作成します:
touch server.js
次に、ファイルでウェブサーバーを設定します:
const express = require('express');
const app = express();
HTML、CSS、JavaScript、画像などの静的アセットをpublic
ディレクトリから提供するように__Express__を設定します:
const express = require('express');
const path = require('path');
const app = express();
app.use(express.static(path.join(__dirname, 'public')))
public
ディレクトリを作成します:
mkdir public
cd public
__Matterport__アプリケーションのHTML、CSS、JavaScriptを追加する空のファイルを作成します:
touch app.js
touch index.html
touch styles.css
cd ..
アプリのHTMLファイルを提供するルートを作成します:
// ...
app.get('/', (req, res) => {
res.sendFile(`${__dirname}/public/index.html`);
});
最後に、ポート「8000」にリスナーを設定して__Express__ウェブサーバーを起動しましょう:
// ...
app.listen(8000, () => {
console.log('Application listening on port 8000!');
});
ウェブサーバーの起動
ウェブサーバーを起動するには、次のコマンドを実行します:
node server.js
これで「 http://localhost:8000 」のブラウザーでアプリにアクセスできます。
Matterport SDK for Embeds
__Matterport__のウェブサイトには、実際に補完的な2つのSDKがリストされています:
- Matterport SDK for Embeds:基本的な__マーターポートの3D Showcase SDK__を使用すると、Web アプリケーションは、エンド・ユーザーの位置と__3Dショーケース__での表示内容を変更するアクションを実行し、ユーザーの位置とユーザーが表示または実行していることに関するイベントをリッスンし、適切に反応できます。
- Matterport SDK Bundle:組み込み用の__SDK for embeds__の拡張で、マーターポート・モデルとのサードパーティとの緊密な統合と、3Dエンジン、レンダラー、シーン グラフなどへの直接アクセスのためのフレームワークを提供します。
第1のアプリを作成するには、(無料の)サンドボックス・アクセスで埋め込み用の__SDK for Embeds__を使用します ...
無料利用枠
無料のサブスクリプション プランでは、サンドボックス モードの開発者ツールに制限付きでアクセスできます:
- SDKのキーは
localhost
でのみ使用できます。他のドメインでは使用できません。 - APIのトークンはデモ・モデルに対してのみ使用でき、ユーザーが作成したモデルに対しては使用できません。
それでは、第1のアプリを作成しましょう。
第1のアプリ:基礎
まず、基本的な__Matterport__アプリを作成しましょう ...
HTML
まず、アプリの最小限のページを作成しましょう:
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0, shrink-to-fit=no">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<title>Matterport Test</title>
<script src="/app.js" defer></script>
<link rel="stylesheet" href="/styles.css">
</head>
<body>
</body>
</html>
次に、<head>
タグにJavascriptライブラリを含めて、__3D Showcase SDK__をWebアプリケーションに追加します:
<html lang="en">
<head>
...
<script src='https://static.matterport.com/showcase-sdk/2.0.1-0-g64e7e88/sdk.js'></script>
<script src="/app.js" defer></script>
<link rel="stylesheet" href="/styles.css">
</head>
...
最後に、<iframe>
タグを追加して、ウェブページにマーターポート・スペースを埋め込みます:
...
<body>
<iframe id="showcase" width="960" height="480" title="test" frameBorder="0" allowFullScreen allow="vr"></iframe>
</body>
</html>
<iframe>
の属性を見てみましょう:
-
frameBorder="0"
:<iframe>
の周囲に境界線が描画されないようにします。 -
allowFullScreen
:__フルスクリーンモード__ボタンを表示します。 -
allow="vr"
:いくつかのコード・サンプルで見つかりましたが、何もしていないようです。 -
allow="xr-spatial-tracking"
:xr immersive modeを有効にします(SDK Bundleだけ)。
JavaScript
次は、アプリケーションのJavaScriptコードで:
-
DOMContentLoaded
のイベントまで待ちます。 -
<iframe>
のマーターポート・スペースのソースを設定します。 - マーターポート・スペースを含む
<iframe>
が読み込まれるまで待ちます。 - SDKをマーターポート・スペースに接続します。
"use strict";
const sdkKey = "aaaaXaaaXaaaXaaaaXaaaXaaa"
const modelSid = "SxQL3iGyoDo";
const params = `m=${modelSid}&hr=0&play=1&qs=1`;
var iframe = document.getElementById('showcase');
document.addEventListener("DOMContentLoaded", () => {
iframe.setAttribute('src', `https://my.matterport.com/show/?${params}`);
iframe.addEventListener('load', () => showcaseLoader(iframe));
});
function showcaseLoader(iframe){
try{
window.MP_SDK.connect(iframe, sdkKey, '3.10')
.then(loadedShowcaseHandler)
.catch(console.error);
} catch(e){
console.error(e);
}
}
function loadedShowcaseHandler(mpSdk){
// ...
}
params
内のURLパラメータを見てみましょう:
-
applicationKey=aaaaXaaaXaaaXaaaaXaaaXaaa
:マーターポート・アカウント → 設定 → 開発者ツール、SDKのキー管理で取得したアプリケーションのSDKのキー。 -
hr=0
:画面の下部に__highlight reel__を表示する__open highlights__ボタンを非表示にします。 -
log=0
:ロギングを無効にします? -
m=SxQL3iGyoDo
:表示するモデルのSID。 -
play=1
:1に設定すると、ページの読み込み時に<iframe>
が自動的に読み込まれます。 -
qs=1
:?
アクション
3Dショーケースで実行するアクションを宣言するには、次のように宣言します:
- アクションが成功した場合に何かを行うためのコールバック:
function successCallback(message) { console.log(message); }
- アクションが失敗した場合に何かを行うためのコールバック:
function errorCallback(error) { console.error(error); }
- 必要な引数を指定してアクションを呼び出します:
mpSdk.<moduleName>.<actionName>(<actionArguments>).then(successCallback)
.catch(errorCallback);
__アクション__は各モジュールのリファレンス。ドキュメントの__関数__セクションにリストされています。
例:モデルへのMattertagの追加
ラベル、説明、ステム、および画像を使用してMattertagを作成するには、次のオブジェクトを宣言します:
var myMattertag = {
label: 'A Tool',
description: 'A cute little vacuum cleaner!',
media: {
type: mpSdk.Mattertag.MediaType.PHOTO,
src: 'https://media.4rgos.it/i/Argos/8086071_R_Z001A',
},
anchorPosition: { x: -3.156, y: 0.363, z: 3.082 },
stemVector: { x: -0.822, y: -0.041, z: 0.568 }
};
⚠️ 画像や動画のメディア ソースとしてローカル URL を使用することはできません!
※ Mattertag
のアンカー位置、stemVector、floorId を見つけるには、Mattertagを作成するではIntersection Inspector Toolを使用することをお勧めしますが、Transient Tags Editorの方がはるかに優れた使いやすいツールです!
※ 画像またはビデオ メディアを表示するには、__Matterport__はembed.lyを使用します。メディア ソースとして設定する前に、embedly exploreの表示ツールで画像またはビデオの URL を確認することをお勧めします。
次に、Mattertag
モジュールからadd
関数を呼び出します;
mpSdk.Mattertag.add(myMattertag)
.then(function(mattertagId) {
console.log(mattertagId);
// ...
})
.catch(function(error) {
console.error(error);
// ...
});
イベント
3Dショーケースからのイベントをリッスンするには、グローバルon
関数を使用します。
showcase.on(<eventName>, function (<stateArguments>) {
// what to do when this event happens
});
※ 3Dショーケースからのイベントのリッスンを停止するには、グローバルoff
関数を使用します。
__イベント__は各モジュールのリファレンス。ドキュメントの__列挙__セクションにリストされています。
例:Mattertagでのclickイベントの検出
mpSdk.Mattertag.Event.CLICK
引数を指定してグローバルon
関数を呼び出し、イベント ハンドラー コールバックの引数を確認します:
mpSdk.on(mpSdk.Mattertag.Event.CLICK,
function (tagSid) {
console.log('Mattertag ' + tagSid + ' was selected');
}
);
カスタマイズ
このセクションでは、__マーターポートSDK__のインタラクティブ性を強化する方法について説明します。
iframeでclickイベントの傍受
ユーザーが<iframe>
をクリックすると、現在のウィンドウでblur
イベントをトリガーする フォカス が取得されます。
⚠️ 最初のclick
イベントの後、フォーカスをwindow
に戻す必要があることに注意してください。そうしないと、2番目のclick
イベントがblur
イベントをトリガーしないことに注意してください!
⚠️ 左クリック、中クリック、右クリックの区別がつきません!
次に、クリックがマーターオートの<iframe>
内で発生したことを確認する必要があります ...
方法1:mouseoverのイベント
click
イベントがマッターポートの<iframe>
で発生したかどうかを知るには、それをcontainer
に埋め込みます:
...
<body>
<div id="container">
<iframe id="showcase" ...></iframe>
</div>
</body>
</html>
そして、mouseover
イベントとmouseout
イベントをリッスンして、状態オブジェクト内のマウス ポインターの位置を追跡します:
var stateObject = {
isMouseOverIframe : false
}
window.addEventListener('blur',function(){
if(stateObject.isMouseOverIframe){
console.log('Yes! The click happened inside the iframe!');
window.focus()
}
});
document.getElementById('container').addEventListener('mouseover',function(){
stateObject.isMouseOverIframe = true;
});
document.getElementById('container').addEventListener('mouseout',function(){
stateObject.isMouseOverIframe = false;
});
⚠️
モバイルの場合、touchstart
やtouchend
などのタッチ・イベントを処理する必要があります。
方法2:document.activeElement
マーターポートの<iframe>
でclick
イベントが発生したかどうかを知るにはdocument.activeElement
がiframe
変数によって参照される要素と同じであることを確認します:
window.addEventListener('blur',function(){
window.setTimeout(function () {
if (document.activeElement === iframe) {
console.log('Yes! The click happened inside the iframe!');
window.focus()
}
}, 0);
});
※ __Firefox__で機能させるには、0秒のsetTimeout
を使用します。
モデルにマッタータグを視覚的に挿入
__JSFiddle__で公的にホストされているIntersection Inspectorのソースコードとは異なり、Transient Tags Editorのアプリのソースコードは__github__で非公開でホストされています(Firefoxでは完全に動作しないため?)。
しかし、Transient Tags Editorの使いやすさに興味をそそられ、マーターポートSDKが提供する2つのツールの違いを理解して、マータータグ座標を見つけたいと思いました。
Intersection Inspector の仕組み
Intersection Inspectorは、__タイマー__を使用して、ユーザーが 1 秒以上Pointer
を動かさないと、ポインターの位置にボタンを表示します。ユーザーはボタンをクリックして__Mattertag__座標を表示し、手動でコピーすることができます ...
これを実現するには、カメラのpose
プロパティを観察して取得する現在のCamera
位置が必要です:
var poseCache;
mpSdk.Camera.pose.subscribe(function(pose) {
poseCache = pose;
});
また、ポインターのintersection
交差プロパティを観察して取得する現在のPointer
位置も必要です:
var intersectionCache;
mpSdk.Pointer.intersection.subscribe(function(intersection) {
intersectionCache = intersection;
intersectionCache.time = new Date().getTime();
button.style.display = 'none';
buttonDisplayed = false;
});
※ ユーザーがポインターを移動するとintersection
イベントがトリガーされるため、1 秒の遅延が経過する前にボタンが表示されないようにボタンを非表示にします。
次に、setInterval()
を使用して__タイマー__を設定し、適切な時間にボタンを表示します:
setInterval(() => {
// ...
}, 16);
タイマー コールバックでは、ボタンを表示するためのすべての条件が満たされているかどうかを確認します ...
- まず、必要な情報があることを確認します:
setInterval(() => {
if (!intersectionCache || !poseCache) {
return;
}
// ...
}, 16);
- 次に、最後の
intersection
イベントが受信されてから1秒が経過したかどうかを確認するか、次のティックを待って再度確認します;
var delayBeforeShow = 1000;
setInterval(() => {
if (!intersectionCache || !poseCache) {
return;
}
const nextShow = intersectionCache.time + delayBeforeShow;
if (new Date().getTime() > nextShow) {
// ...
}
}, 16);
- 最後に、ボタンがまだ表示されていないことを確認します:
var delayBeforeShow = 1000;
var buttonDisplayed = false;
setInterval(() => {
if (!intersectionCache || !poseCache) {
return;
}
const nextShow = intersectionCache.time + delayBeforeShow;
if (new Date().getTime() > nextShow) {
if (buttonDisplayed) {
return;
}
// ...
}
}, 16);
条件が満たされたら、Conversion.worldToScreen()
を使用してボタンを表示し、ポインターの画面座標を取得できます:
// ...
setInterval(() => {
// ...
if (new Date().getTime() > nextShow) {
// ...
var size = {
w: iframe.clientWidth,
h: iframe.clientHeight,
};
var coord = mpSdk.Conversion.worldToScreen(intersectionCache.position, poseCache, size);
button.style.left = `${coord.x - 25}px`;
button.style.top = `${coord.y - 22}px`;
button.style.display = 'block';
buttonDisplayed = true;
}
}, 16);
このボタンは、デフォルトではdisplay: none;
を使用して非表示にされ、position: absolute;
を使用して本文に対して相対的に配置される単純な HTML ボタンです。
ユーザーがボタンをクリックすると、ポインタの現在の座標が<iframe>
の上の<div>
タグに表示され、ボタンが非表示になります:
button.addEventListener('click', function() {
text.innerHTML = `position: ${pointToString(intersectionCache.position)}\nnormal: ${pointToString(intersectionCache.normal)}\nfloorId: ${intersectionCache.floorId}`;
button.style.display = 'none';
iframe.focus();
});
座標は、次の関数を使用してフォーマットされます:
function pointToString(point) {
var x = point.x.toFixed(3);
var y = point.y.toFixed(3);
var z = point.z.toFixed(3);
return `{ x: ${x}, y: ${y}, z: ${z} }`;
}
では、より使いやすく、使いやすいTransient Tags Editorのインターフェイスがどのように機能するかを見てみましょう ...
Transient Tag Editor の仕組み
アプリケーションのいくつかのモデルに永続的に設定する__マッタータグ__がいくつかある場合は、Intersection Inspectorで十分です。ただし、ユーザーがモデルにインタラクティブにタグを設定する必要がある場合は、Transient Tags EditorのGUIのようなものが開始点として適しています。
Transient Tags Editorを使用する主な利点は、Mattertag
がどのように表示されるかを作成前に確認できることです。こうすることで、試行錯誤することなく正確にタグを配置することができます ...
タグを追加するには、「新しいタグを配置」ボタンをクリックして「タグの追加」モードに入る必要があります。その後、必要な場所に新しいタグを1つ配置できます。
エディターのその側面にのみ焦点を当て、タグを追加するだけの簡単なサンプルを作成します:
- 「タグの追加」モードでユーザーがポインターに沿ってタグを移動すると、最初のステップは新しいタグを作成して配置することです。
Mattertag.add()
を使用して、そのための関数を作成しましょう:
function addTag() {
if(!tag){
mpSdk.Mattertag.add([{
label: "Matterport Tag",
description: "",
anchorPosition: {x: 0, y: 0, z: 0},
stemVector: {x:0, y: 0, z: 0},
color: {r: 1, g: 0, b: 0},
}])
.then((sid) => {
tag = sid[0];
})
.catch( (e) => {
console.error(e);
})
}
}
- 次に、ポインターの近くにタグを配置し、ユーザーがポインターを移動するとその位置を更新する必要があるため、
Mattertag.editPosition()
を使用してそのための関数を作成しましょう:
function updateTagPos(newPos, newNorm=undefined, scale=undefined){
if(!newPos) return;
if(!scale) scale = .33;
if(!newNorm) newNorm = {x: 0, y: 1, z: 0};
mpSdk.Mattertag.editPosition(tag, {
anchorPosition: newPos,
stemVector: {
x: scale * newNorm.x,
y: scale * newNorm.y,
z: scale * newNorm.z,
}
})
.catch(e =>{
console.error(e);
tag = null;
});
}
ご覧のとおりupdateTagPos()
関数は 3 つのパラメーターを受け取ります:
-
newPos:
Mattertag
の新しいアンカー位置。 -
newNorm:
Mattertag
の新しいステム・ベクトルのオプション。 -
scale:
Mattertag
のステム用の新しいスケールのオプション。
- ユーザーがポインターを移動したときにタグの位置を更新するには、ポインターの
intersection
交差プロパティを観察してupdateTagPos()
を呼び出します:
mpSdk.Pointer.intersection.subscribe(intersectionData => {
if(tag){
if(intersectionData.object === 'intersectedobject.model' || intersectionData.object === 'intersectedobject.sweep'){
updateTagPos(intersectionData.position, intersectionData.normal);
}
}
});
- 新しいタグを配置するには、ユーザーがマウス ボタンをクリックするだけです。Transient Tags Editorは、
<iframe>
でのクリックをインターセプトする独自のバージョンのdocument.activeElement
方法を提供します_(ただし、__Firefox__では機能しないため、エディターは非常に複雑な回避策)_:
function focusDetect(){
const eventListener = window.addEventListener('blur', function() {
if (document.activeElement === iframe) {
placeTag(); //function you want to call on click
setTimeout(function(){ window.focus(); }, 0);
}
window.removeEventListener('blur', eventListener );
});
}
ただし、__Firefox__でより適切に動作するバージョンを使用します (ただし、何らかの理由で__Firefox__で最初にクリックした後は動作を停止します):
window.addEventListener('blur',function(){
window.setTimeout(function () {
if (document.activeElement === iframe) {
placeTag(); //function you want to call on click
window.focus()
addTag();
}
}, 0);
});
- 最後に、
Mattertag.navigateToTag()
を使用して、新しいタグに移動してその__billboard(看板)を開く__関数を作成しましょう:
function placeTag(){
if(tag) mpSdk.Mattertag.navigateToTag(tag, mpSdk.Mattertag.Transition.INSTANT);
tag = null;
}
単純なエディターのサンプル
まず、全てのJavaScriptソースコード:
"use strict";
const sdkKey = "aaaaXaaaXaaaXaaaXaaaXaaa"
const modelSid = "iL4RdJqi2yK";
let iframe;
let tag;
document.addEventListener("DOMContentLoaded", () => {
iframe = document.querySelector('.showcase');
iframe.setAttribute('src', `https://my.matterport.com/show/?m=${modelSid}&help=0&play=1&qs=1>=0&hr=0`);
iframe.addEventListener('load', () => showcaseLoader(iframe));
});
function showcaseLoader(iframe){
try{
window.MP_SDK.connect(iframe, sdkKey, '3.10')
.then(loadedShowcaseHandler)
.catch(console.error);
} catch(e){
console.error(e);
}
}
function loadedShowcaseHandler(mpSdk){
addTag()
function placeTag(){
if(tag) mpSdk.Mattertag.navigateToTag(tag, mpSdk.Mattertag.Transition.INSTANT);
tag = null;
}
window.addEventListener('blur',function(){
window.setTimeout(function () {
if (document.activeElement === iframe) {
placeTag(); //function you want to call on click
window.focus()
addTag();
}
}, 0);
});
function updateTagPos(newPos, newNorm=undefined, scale=undefined){
if(!newPos) return;
if(!scale) scale = .33;
if(!newNorm) newNorm = {x: 0, y: 1, z: 0};
mpSdk.Mattertag.editPosition(tag, {
anchorPosition: newPos,
stemVector: {
x: scale * newNorm.x,
y: scale * newNorm.y,
z: scale * newNorm.z,
}
})
.catch(e =>{
console.error(e);
tag = null;
});
}
mpSdk.Pointer.intersection.subscribe(intersectionData => {
if(tag){
if(intersectionData.object === 'intersectedobject.model' || intersectionData.object === 'intersectedobject.sweep'){
updateTagPos(intersectionData.position, intersectionData.normal);
}
}
});
function addTag() {
if(!tag){
mpSdk.Mattertag.add([{
label: "Matterport Tag",
description: "",
anchorPosition: {x: 0, y: 0, z: 0},
stemVector: {x:0, y: 0, z: 0},
color: {r: 1, g: 0, b: 0},
}])
.then((sid) => {
tag = sid[0];
})
.catch( (e) => {
console.error(e);
})
}
}
} // loadedShowcaseHandler
HTMLのソースコード:
<!DOCTYPE html>
<html>
<head>
<title>Transient Tag Editor</title>
<style>
#showcase {
width: 100%;
height: 100vh;
}
</style>
<script src="https://static.matterport.com/showcase-sdk/2.0.1-0-g64e7e88/sdk.js"></script>
<script src="/js/app-editor.js" type="text/javascript" defer></script>
</head>
<body>
<iframe id="showcase" frameborder="0" allowFullScreen allow="xr-spatial-tracking"></iframe>
</body>
</html>
やった!
Matterport SDK Bundle
第2のアプリを作成するために、今回は__SDK Bundle__を使用しますが、まだ(無料の)サンドボックス・アクセスです ..
まず、最新のSDK Bundleのパケージをダウンロードします。
次に、第2のアプリケーションの2つ目のルートを処理するようにサーバーを更新しましょう ...
ウェブサーバー
バンドル アプリのルートを追加しましょう:
// ...
app.get('/bundle', (req, res) => {
res.sendFile(`${__dirname}/public/index-bundle.html`);
});
app.listen(8000, () => {
console.log('Application listening on port 8000!');
});
その後、ウェブサーバーを再起動して ...
第2のアプリ:基礎
最初のものと似ているので、別の基本的な__Matterport__アプリを作成しましょう。最初のアプリ ファイルをコピーして名前を変更できます ...
HTML
まず、index.html
ファイルをコピーして、index-bundle.html
に名前を変更します:
JavaScriptのファイル名をapp-bundle.js
に変更します:
...
<script src="/app-bundle.js" defer></script>
...
JavaScript
それでは、app.js
ファイルをコピーして、app-bundle.js
に名前を変更しましょう。
そこで、iframeのsourceURLを/bundle/showcase.html?${params}
に変更します:
// ...
document.addEventListener("DOMContentLoaded", () => {
iframe.setAttribute('src', `/bundle/showcase.html?${params}`);
iframe.addEventListener('load', () => showcaseLoader(iframe));
});
// ...
そして、connect
ステートメントを次のように変更しますiframe.contentWindow.MP_SDK.connect
:
// ...
function showcaseLoader(iframe){
try{
iframe.contentWindow.MP_SDK.connect(iframe, sdkKey, '3.10')
.then(loadedShowcaseHandler)
.catch(console.error);
} catch(e){
console.error(e);
}
}
// ...
シーン
__SDK Bundle__は、標準のSDKに追加のモジュールであるScene
モジュールを提供します。
ライティング
シーンにはライトが必要です。ライトがない場合、モデルは黒で表示されます。
__Matterport__は、このためにmp.lights
と呼ばれる基本的なライト コンポーネントを提供します。Scene.createNode()
を使用してシーンにノードを作成し、INode.addComponent()
を使用してコンポーネントをそれにアタッチしましょう:
const lights = await mpSdk.Scene.createNode();
lights.addComponent('mp.lights');
lights.start();
※
コンポーネントで INode.start()
を呼び出して、動作を開始します。
モデル
__SDK Bundle__は、次のシーンおよびモデル アセット タイプのロードをサポートしています:
-
dae、
mpSdk.Scene.Component.DAE_LOADER
で -
fbx、
mpSdk.Scene.Component.FBX_LOADER
で -
obj、
mpSdk.Scene.Component.OBJ_LOADER
で -
gltf、
mpSdk.Scene.Component.GLTF_LOADER
で
モデルは、照明コンポーネントのようなコンポーネントとしてシーンに追加されます:
// ...
const modelNode = await mpSdk.Scene.createNode();
const fbxComponent = modelNode.addComponent(mpSdk.Scene.Component.DAE_LOADER, {
url: 'https://gitcdn.link/repo/mrdoob/three.js/dev/examples/models/collada/stormtrooper/stormtrooper.dae',
});
※ __SDK Bundle__ドキュメントのチュートリアルWorking With Models(モデルの操作)にいくつかのモデルがリストされています。
拡大縮小
一部のモデルは実世界の単位に調整されていないため、モデルをスケーリングしてより現実的なサイズに調整する必要がある場合があります:
// ...
fbxComponent.inputs.localScale = {
x: 0.3,
y: 0.3,
z: 0.3
};
ポジショニング、按排
デフォルトの位置は(0, 0, 0)ですが、ストームトルーパーを空中に浮かせたくない場合は、それを下げる必要があります:
// ...
modelNode.obj3D.position.set(0,-1.65,0);
回転
ストームトルーパーのモデルは、y軸に沿った角度が0の場合はカメラの方を向き、角度が𝜋
の場合はカメラの方を向きます:
// ...
modelNode.obj3D.rotation.y = Math.PI
※ __Matterport__は、__Three.js__のように、角度を指定するためにラジアンを使用していました。
アクティベート
照明コンポーネントと同様に、INode.start()
を使用してモデルをアクティブ化する必要があります:
// ...
modelNode.start();
第2のアプリ: まとめ
2番目のアプリを完成させましょう ...
アニメーション
モデルをアニメーション化するには、単にrequestAnimationFrame()
関数を使用します。
ストームトルーパーを前後に動かしながらゆっくり回転させましょう:
// ...
let step = -0.1
let zPos = 0
const tick = function() {
requestAnimationFrame(tick);
if (zPos>= 1.8) {
step = -0.02
} else if (zPos <= -0.4) {
step = 0.02
}
zPos += step
modelNode.obj3D.rotation.y += 0.02;
modelNode.obj3D.position.set(0,-1.65,zPos);
}
tick();
JavaScriptコードのまとめ
すべてをapp-bundle.js
ファイルにまとめましょう:
"use strict";
const sdkKey = "aaaaXaaaXaaaXaaaaXaaaXaaa"
const modelSid = "22Ub5eknCVx";
const params = `m=${modelSid}&play=1&qs=1&log=0&applicationKey=${sdkKey}`;
var iframe = document.getElementById('showcase');
document.addEventListener("DOMContentLoaded", () => {
iframe.setAttribute('src', `/bundle/showcase.html?${params}`);
iframe.addEventListener('load', () => showcaseLoader(iframe));
});
function showcaseLoader(iframe){
try{
iframe.contentWindow.MP_SDK.connect(iframe, sdkKey, '3.10')
.then(loadedShowcaseHandler)
.catch(console.error);
} catch(e){
console.error(e);
}
}
async function loadedShowcaseHandler(mpSdk){
const lights = await mpSdk.Scene.createNode();
lights.addComponent('mp.lights');
lights.start();
const modelNode = await mpSdk.Scene.createNode();
const fbxComponent = modelNode.addComponent(mpSdk.Scene.Component.DAE_LOADER, {
url: 'https://gitcdn.link/repo/mrdoob/three.js/dev/examples/models/collada/stormtrooper/stormtrooper.dae',
});
fbxComponent.inputs.localScale = {
x: 0.3,
y: 0.3,
z: 0.3
};
modelNode.obj3D.position.set(0,-1.65,0);
modelNode.obj3D.rotation.y = Math.PI
modelNode.start();
let step = -0.1
let zPos = 0
const tick = function() {
requestAnimationFrame(tick);
if (zPos>= 1.8) {
step = -0.02
} else if (zPos <= -0.4) {
step = 0.02
}
zPos += step
modelNode.obj3D.rotation.y += 0.02;
modelNode.obj3D.position.set(0,-1.65,zPos);
}
tick();
}
Matterport Model API
このチュートリアルで検討した 2 つの SDK に加えて、__Matterport__は__API Token__を使用するModel API__と呼ばれる__GraphQL APIも提供します。SDKとの違いはFAQで説明されています。
管理者権限でMatterport Cloud(my.matterport.com)にログインしているユーザーは定的に__GraphQL API__を試すことができる__インタラクティブ・コンソール__がreference documentationとともに利用できます。
全てのコード
すべてのサンプルのコードは、__github__で入手できます:
github.com/loic-meister-guild/pj-matterport-sdk-2021-tutorial