VRED Core Stream インタラクションのためのカスタム HTML オーバーレイ UI の記述方法について説明します。
ビデオ キャプション: VRED Core のチュートリアルへようこそ。Christopher といいます。本日は、VRED Core アプリケーション用の簡単なカスタム HTML インタフェースの作成方法を説明します。
VRED Core はさまざまなニーズに最適となるように開発されました。レンダリング パイプラインやデータ準備パイプライン、または専用のリアルタイム レンダリング サーバとしての機能を提供することで、さまざまなユース ケースに対応しています。VRED Core は独自のユーザ インタフェースを提供しないため、Python Web インタフェースを使用して VRED Core と通信する必要があります。
ただし、VRED Core にはストリーミング アプリが付属していて、製品のプレゼンテーションやデザイン レビューに必要なすべての機能にアクセスできます。ストリーミング アプリを使用すると、シーン内のすべてのバリアント セットとビューポイントにアクセスでき、カメラを自由にナビゲートすることもできます。これは多くのアプリケーションに使用できますが、完全にカスタマイズされた HTML ユーザ インタフェースを自分で構築できるツールも備えています。つまり、ニーズを完全に満たし、企業のデザインでブランド化できるアプリケーションを構築することができます。
このチュートリアルでは、ライブ ビデオ ストリーム、簡単な Python ターミナル、バリアント セットのリストなど、独自の VRED アプリを構築する方法を紹介します。VRED との通信を確立するために、Python のエンドポイントを使用します。
最初に、簡単なテキスト段落を含む HTML ドキュメントを作成します。このドキュメントに index.html という名前を付けることはできません。この名前は既に予約されています。そこで、myapp.html という名前を付けます。
次に、HTML Web インタフェースの基本設定を設定する必要があります。これは、コマンド ライン パラメータ editPreferences を使用して VRED Core を開始することで実行できます。基本設定の[Web インタフェース]タブに切り替えて、次の設定を行います。ファイル アクセスを有効にして、カスタム アプリが存在するディレクトリにディレクトリを設定します。下にある、[クロスオリジン リクエストを有効化]を有効にします。ポート番号を 8888 以外に設定した場合は、VRED に対する Python リクエストに必要となるため、そのポート番号をメモしてください。
これらの設定は VRED の Web インタフェースを初期化します。設定を調整するには、VRED Core を実行して、ローカルホストとアプリ myapp.html で提供されるポートを使用してブラウザを開きます。これで、サンプル テキストが表示され、Web インタフェースが正しく動作していることが分かります。その後、エディタに戻ってアプリの実装を続けることができます。
最初に、ナビゲーションを使用してライブ ビデオ ストリームを実装します。これを行うにはいくつかの方法がありますが、わかりやすくするために、エンドポイント アプリの VRED ストリームで提供されているストリームを使用することができます。このエンドポイントは、ライブ ビデオ ストリームと、VRED Pro と Designer で知られている既定のナビゲーション動作を提供します。
このエンドポイントを、ページ全体をカバーするように構成できる iframe のソースとして使用できます。これを行うには、スクリプトを作成します。このスクリプトはドキュメントから引用したもので、そこにいくつかの javascript コードを追加し、ID ストリーム コンテナを持つ要素を検索する initializeStream 関数を再作成しし、そのソースをストリーミング エンドポイントに設定します。ここでは、Web 基本設定で設定したポート番号を使用します。
windowUnload 関数内で関数を呼び出し、ページがロードされたときにストリームが常に初期化されるようにします。もちろん、このビデオ ストリームで表示される ID アトリビュートが一致する iframe 要素も必要です。一部の CSS では、iframe のサイズを 100% に設定し、境界やスクロール バーが表示されないようにします。
ブラウザにアプリをロードして、ストリームが正しく動作しているかどうかを確認します。うまくできました。VRED へのライブ ビデオ ストリームが追加され、マウスを使用してシーンをナビゲートできるようになりました。
ライブ ビデオ ストリームを用意することは最初のステップですが、もちろん、アプリ内でいくつかのインタラクションを実装することもできます。このチュートリアルでは、単純な Python ターミナルを統合し、VRED に Python コマンドを送信してシーンを操作できるようにする方法を説明します。
まず、ビデオ ストリーム上に Python ターミナルを配置できる新しい div コンテナをいくつか追加します。次に、テキスト入力とボタンを追加し、入力要素のコンテンツを javascript 関数に追加します。また、VRED から送信される戻り値を表示するために、入力フィールドとボタンの下にテキスト領域を追加します。これらの新しい div コンテナのスタイルを設定し、Python インタフェースをブラウザ ウィンドウの右下隅に配置します。
Python コマンドを送信するために、javascript 領域に sendAndReceivePython という名前の新しい関数を作成できます。また、この関数は XML HTTP 要求オブジェクトを使用して、Python エンドポイントである pythoneval2 に GET 要求を送信します。このエンドポイントは Python コマンドを受け入れ、また、Python 操作の結果も文字列として返します。
この時点で、将来簡単に変更できる個別の変数でポートとホストを並べ替えます。VRED が認識できるように、Python コマンドを URI としてエンコードしてください。
また、より柔軟に処理できるよう、success および error コールバック関数も使用します。successCallback は GET 要求に応じて呼び出され、errorCallback はエラーの場合に呼び出されます。
次に、実際に Python コマンドを VRED に送信し、結果メッセージをテキスト領域の要素に添付する関数 executeTerminalCode を実装します。[送信]ボタンをクリックして入力フィールドのコンテンツをパラメータとして渡すときに関数を呼び出す必要があります。すべてを正しく接続すると、単純な出力コマンドを VRED に送信したり、シーンからすべてのバリアント セットを要求したりできるようになります。
バリアント セットのリストは Python ターミナル ウィンドウにも表示されます。これは、VRED が返信メッセージとともにバリアント セットのリストを返すためです。アプリで利用可能なすべてのバリアント セットのリストを取得できることが分かりました。では、それらをインタフェースに表示して選択可能にしてみましょう。
updateVariantSets という新しい javascript 関数を作成してみましょう。この関数では、Python コマンド getVariantSets を使用して send and receive Python 関数を呼び出し、応答に対するコールバック メソッドを提供します。
ここでは、単にバリアント セットをコンソールに出力します。この関数を windowUnload 関数で呼び出し、Web ページを再ロードします。ブラウザで[F12]を押すと、Web ページのコンソールを開くことができます。ページを再ロードまたは開くと、現在ロードされているシーンにバリアント セットのリストが表示されます。バリアント セットがない場合、ここに空のエラーが表示されます。
ここでは、さまざまなバリアント セットを含む VRED の Genesis のサンプルをテストします。アプリはすべてのバリアント セットをリストとして既に受け取っていますが、HTML にも追加する必要があります。次の手順では、ID バリアント セット コンテナを持つ別の div コンテナを HTML に追加します。このコンテナは、VRED から受け取るすべてのバリアント セットのリストを保持します。
updateVariantSets 関数に戻り、まず、eval 関数を使用してバリアント セット アレイを実際の javascript アレイとして渡す必要があります。次に、getElementID 関数を使用してコンテナへの参照を取得します。すべてのバリアント セット アレイを反復して HTML 要素ノードを作成し、このノードをコンテナに追加できます。
また、バリアント セット名をクリックして、VRED で選択できるようにします。これを行うには、バリアント セット ノードに onClick 関数を追加します。ユーザがバリアント セット ノードをクリックするたびに、selectVariantSet パラメータとバリアント セットの名前を使用して sendAndReceive Python 関数を呼び出します。次に、いくつかの CSS を追加して、新しいバリアント セットリストをページに配置します。今度は、左側です。ページを再ロードすると、左側にバリアント セットのリストが表示されます。いずれかのバリアント セットをクリックすると、VRED でもバリアント セットが選択されます。
このチュートリアルでは、簡単な HTML、javascript、および CSS を使用して、完全にカスタマイズされたストリーミング アプリを最初から作成しました。VRED Core は複数のエンドポイントを提供します。これらのエンドポイントを使用してナビゲーション付きのライブ ビデオ ストリームを追加し、Python コマンドを使用して VRED で要求データを変更します。その他にも多くの機能がありますが、それらすべてについて説明することはここでの目的ではありません。
次のチュートリアルでは、HTML アプリを拡張し、新しい Web API を使用していくつかの機能を実装します。今日の説明はこれで終わりです。ご参加いただき、ありがとうございました。またお会いしましょう。
これは、「チュートリアル 5: VRED Core Stream インタラクションのためのカスタム HTML オーバーレイ UI の記述方法」ビデオに付属する Python サンプル スクリプトです。
以下のファイルが含まれた ZIP ファイルをダウンロードするには、ここをクリックしてください。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>My Custom App</title>
</head>
<body>
<p>This is my custom VRED App</p>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>My Custom App</title>
<style>
html, body {
padding: 0;
margin: 0;
width: 100vw;
height: 100vh;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif
}
#page {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
#stream-container {
width: 100%;
height: 100%;
overflow: hidden;
}
</style>
<script>
function initializeStream() {
document.getElementById("stream-container").src = "http://localhost:8888/apps/VREDStream/index.html";
}
window.onload = function() {
initializeStream();
updateVariantSes();
}
</script>
</head>
<body>
<div id="page">
<iframe id="stream-container" frameborder="0" overflow="hidden" scroll="no"></iframe>
</div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>My Custom App</title>
<style>
html, body {
padding: 0;
margin: 0;
width: 100vw;
height: 100vh;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif
}
#page {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
#stream-container {
width: 100%;
height: 100%;
overflow: hidden;
}
.python-interface {
padding: 1em 2em;
position: absolute;
right: 1em;
bottom: 1em;
background-color: #2d2d2d;
display: flex;
flex-direction: column;
}
.python-send-wrapper {
margin-bottom: 0.5em;
}
.python-send-wrapper > input {
width: 25em;
}
#python-response {
height: 10em;
resize: none;
}
</style>
<script>
var host = "localhost";
var port = "8888";
function initializeStream() {
document.getElementById("stream-container").src = 'http://' + host + ':' + port + '/apps/VREDStream/index.html';
}
function executeTerminalCode(python) {
console.log(python);
sendAndReceivePython(python,
(response) => {
var text = document.getElementById('python-response').value;
text += '\n' + response;
document.getElementById('python-response').value = text;
},
(error) => console.error("Error sending pyhton command.", python)
);
}
function sendAndReceivePython(command, successCallback, errorCallback) {
var http = new XMLHttpRequest();
var url = 'http://' + host + ':' + port + '/pythoneval2?value=' + encodeURI(command);
http.open('GET', url, true);
http.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
if(this.responseText && successCallback) {
successCallback(this.responseText)
}
}
};
http.onerror = function() {
if(errorCallback) {
errorCallback();
}
}
http.send();
}
window.onload = function() {
initializeStream();
}
</script>
</head>
<body>
<div id="page">
Variant Set Container
<div id="variant-set-container"></div>
Video Stream Container
<iframe id="stream-container" frameborder="0" overflow="hidden" scroll="no"></iframe>
Python Terminal Container
<div class="python-interface">
<div class="python-send-wrapper">
<input id="python-value" type="text" placeholder="Enter your python code..."></input>
<button onclick="executeTerminalCode(document.getElementById('python-value').value)">Send Python</button>
</div>
<textarea id="python-response"></textarea>
</div>
</div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>My Custom App</title>
<style>
html, body {
padding: 0;
margin: 0;
width: 100vw;
height: 100vh;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif
}
#page {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
#stream-container {
width: 100%;
height: 100%;
overflow: hidden;
}
.python-interface {
padding: 1em 2em;
position: absolute;
right: 1em;
bottom: 1em;
background-color: #2d2d2d;
display: flex;
flex-direction: column;
}
.python-send-wrapper {
margin-bottom: 0.5em;
}
.python-send-wrapper > input {
width: 25em;
}
textarea#python-response {
height: 10em;
resize: none;
}
</style>
<script>
var host = "localhost";
var port = "8888";
function initializeStream() {
document.getElementById("stream-container").src = 'http://' + host + ':' + port + '/apps/VREDStream/index.html';
}
function updateVariantSets() {
sendAndReceivePython("getVariantSets()",
(response) => {
console.log(response);
}
);
}
function executeTerminalCode(python) {
console.log(python);
sendAndReceivePython(python,
(response) => {
var text = document.getElementById('python-response').value;
text += '\n' + response;
document.getElementById('python-response').value = text;
},
(error) => console.error("Error sending pyhton command.", python)
);
}
function sendAndReceivePython(command, successCallback, errorCallback) {
var http = new XMLHttpRequest();
var url = 'http://' + host + ':' + port + '/pythoneval2?value=' + encodeURI(command);
http.open('GET', url, true);
http.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
if(this.responseText && successCallback) {
successCallback(this.responseText)
}
}
};
http.onerror = function() {
if(errorCallback) {
errorCallback();
}
}
http.send();
}
window.onload = function() {
initializeStream();
updateVariantSets();
}
</script>
</head>
<body>
<div id="page">
Variant Set Container
<div id="variant-set-container"></div>
Video Stream Container
<iframe id="stream-container" frameborder="0" overflow="hidden" scroll="no"></iframe>
Python Terminal Container
<div class="python-interface">
<div class="python-send-wrapper">
<input id="python-value" type="text" placeholder="Enter your python code..."></input>
<button onclick="executeTerminalCode(document.getElementById('python-value').value)">Send Python</button>
</div>
<textarea id="python-response"></textarea>
</div>
</div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>My Custom App</title>
<style>
html, body {
padding: 0;
margin: 0;
width: 100vw;
height: 100vh;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif
}
#page {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
#variant-set-container {
padding: 1em 2em;
position: absolute;
left: 1em;
bottom: 1em;
background-color: #2d2d2d;
display: flex;
flex-direction: column;
height: 20em;
overflow-y: scroll;
color: white;
}
#variant-set-container > div {
padding: 0.1em 0.2em;
background-color: #4b4b4b;
margin-bottom: 0.1em;
cursor: pointer;
}
#stream-container {
width: 100%;
height: 100%;
overflow: hidden;
}
.python-interface {
padding: 1em 2em;
position: absolute;
right: 1em;
bottom: 1em;
background-color: #2d2d2d;
display: flex;
flex-direction: column;
}
.python-send-wrapper {
margin-bottom: 0.5em;
}
.python-send-wrapper > input {
width: 25em;
}
textarea#python-response {
height: 10em;
resize: none;
}
</style>
<script>
var host = "localhost";
var port = "8888";
function initializeStream() {
document.getElementById("stream-container").src = 'http://' + host + ':' + port + '/apps/VREDStream/index.html';
}
function updateVariantSets() {
sendAndReceivePython("getVariantSets()",
(response) => {
var variantSets = eval(response);
if(variantSets) {
// get a reference to our variant set container
var variantSetContainer = document.getElementById('variant-set-container');
// delete variant set list
variantSetContainer.textContent = '';
// add element for each variant set
variantSets.forEach(variantSet => {
var variantSetNode = document.createElement('div');
variantSetNode.innerHTML = variantSet;
variantSetNode.onclick = function() {
sendAndReceivePython("selectVariantSet('"+variantSet+"')");
}
variantSetContainer.appendChild(variantSetNode);
});
}
}
);
}
function executeTerminalCode(python) {
console.log(python);
sendAndReceivePython(python,
(response) => {
var text = document.getElementById('python-response').value;
text += '\n' + response;
document.getElementById('python-response').value = text;
},
(error) => console.error("Error sending pyhton command.", python)
);
}
function sendAndReceivePython(command, successCallback, errorCallback) {
var http = new XMLHttpRequest();
var url = 'http://' + host + ':' + port + '/pythoneval2?value=' + encodeURI(command);
http.open('GET', url, true);
http.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
if(this.responseText && successCallback) {
successCallback(this.responseText)
}
}
};
http.onerror = function() {
if(errorCallback) {
errorCallback();
}
}
http.send();
}
window.onload = function() {
initializeStream();
updateVariantSets();
}
</script>
</head>
<body>
<div id="page">
Variant Set Container
<div id="variant-set-container"></div>
Video Stream Container
<iframe id="stream-container" frameborder="0" overflow="hidden" scroll="no"></iframe>
Python Terminal Container
<div class="python-interface">
<div class="python-send-wrapper">
<input id="python-value" type="text" placeholder="Enter your python code..."></input>
<button onclick="executeTerminalCode(document.getElementById('python-value').value)">Send Python</button>
</div>
<textarea id="python-response"></textarea>
</div>
</div>
</body>
</html>