「チュートリアル 3: VRED でスクリプトを使用する場合(一般的な使用事例)」ビデオの内容は、次のとおりです。
-prepython
および -postpython
ビデオのキャプション: VRED Pro の Python スクリプト作成に関するチュートリアルへようこそ。Christopher といいます。本日は、VRED のさまざまな Python インタフェースと、それらを効率的に使用する方法についてすべてお話します。
VRED には、Python を使用してスクリプトを作成するさまざまな方法が用意されています。また、複数のインタフェースがあって、シーンまたは VRED の動作に一般的に影響を与える Python コードを配置することができます。ただし、すべてのインタフェースが同じタスクに対して適切に動作するわけではありません。インタフェースを切り替えると、問題が効率的に解決される場合があります。ここでは、Python スクリプトを配置するさまざまな場所を、簡単なものから複雑なものまで、すべて紹介します。まず、いくつかのサンプルを見てみましょう。
最初に、VREDにある Python インタフェースの最もシンプルな形式であるターミナルについて説明します。ターミナルは、Python コマンドの入力としても、VRED、他のスクリプト、またはユーザ独自のコードによって生成される出力メッセージの出力としても機能します。VRED の起動後にターミナルを開くと、ロードされているリソースやエラーの有無を示す VRED からの基本的な初期化メッセージが、一連のメッセージとして表示されます。ユーザや他のスクリプトによって生成されたすべての出力メッセージがターミナルに表示されるため、ターミナルを使用する以外の方法で、スクリプトの実行中にエラーの有無を直接確認したり、ログ メッセージを確認したりすることはできません。
また、ターミナルは、インタラクティブ モードの Python インタプリタと同様に、Python コマンドの基本的な入力としても機能します。コマンドを入力すると、正常に実行された場合は緑色のフィードバックが表示され、エラーが発生した場合は赤色のフィードバックが表示されます。ターミナルに入力できるのは 1 行のみであるため、主に Python 関数のテストに使用されます。また、ターミナルで記述した内容は VRED を再起動するとすべて失われるため、ファイルに保存することはできません。ターミナルから、スクリプト エディタ、基本設定、またはバリアント セットでグローバルに定義されている変数や関数にアクセスすることはできますが、ターミナルで定義したすべての変数や関数に他のスクリプトからアクセスすることはできません。
より重要な Python スクリプト インタフェースについて説明する前に、スクリプトの基本設定について調べてみましょう。スクリプトの基本設定とは、VRED アプリケーションの基本設定に保存される Python スクリプトのことで、開いているファイルに関係なく、常に使用できます。スクリプトの基本設定は、カスタム キー マッピングを定義する場合に便利です。初めてスクリプトの基本設定を開いた時点で、レンダリング設定やその他の設定を変更するキー マッピングが[F]キーに定義されています。
スクリプトの基本設定には、常に必要となる小規模な Python スクリプトまたは変数が保管されており、開いたファイルから独立して機能します。たとえば、ターミナル メッセージにタイムスタンプを自動的に追加するカスタム ログ関数を定義することができます。スクリーンショットを作成する関数や、レンダリングのプレビューを行う関数を定義して、ハード ドライブに保存することもできます。しかし、ほとんどの場合は、追加の関数を使用してキー マッピングをカスタマイズする必要があります。たとえば、複数のレンダリング品質の間で切り替える必要があります。スクリプトの基本設定で定義したすべての関数は、スクリプト エディタ、バリアント セット、およびターミナルでグローバルに使用できます。つまり、スクリプトの基本設定で定義されている関数をバリアント セットから直接呼び出すなどの操作を実行できます。
バリアント セットについては、次のトピックでも説明します。バリアント セット内に Python スクリプトを直接記述できます。バリアント セットには[スクリプト]タブが用意されていて、バリアント セットがトリガされたときに実行される Python コードを含めることができます。変数、関数、クラスを定義できますが、ほとんどの場合は、特定の動作を 1 つ実行するスクリプトを記述します。
このサンプルでは、バリアント セットをアクティブにするとトリガされるデータ準備ツールを実装しました。この場合、バリアント セットは、ダブルクリックするだけでトリガできる Python ツールとして機能します。スクリプト自体は、別の CAD ソフトウェアから読み込むときに失われたマテリアルおよびマテリアル スイッチを照合します。特定の名前のマテリアルを検索して、マテリアル スイッチを生成します。その後、破損したマテリアルを新しいマテリアル スイッチに置き換えます。
ご覧のとおり、スクリプトは長すぎることがなく、1 つの問題だけを解決するため、維持するのはとても簡単です。コードと出力メッセージにはコメントが含まれていて、コードを読みやすく、かつ理解しやすくするのに役立っています。また、コードが実際に意図した動作を行ったかどうか、またはエラーが発生したかどうかをユーザが確認する場合にも役立ちます。
バリアント セット内に記述した Python スクリプトは、適用範囲がローカルになります。つまり、変数、関数、クラスは、この特定のバリアント セットでのみ使用できます。バリアント セット B のスクリプトから、バリアント セット A で定義されている関数を呼び出すことはできません。同様に、複数のバリアント セット内のスクリプトを使用する場合は、グローバルに使用可能なスクリプト エディタにこのスクリプトを配置して、バリアント セットから呼び出す必要があります。これにより、コードの重複も防止されます。
最後に、バリアント セットに含めるコードの量にも注意する必要もあります。前のサンプルのコード数は約 40 行でした。この行数であれば、問題ありません。ただし、数百行のコードが含まれているスクリプトがある場合は、基本的に、プログラムを維持し、理解するのは困難になります。このようなコードを拡張したり、エラーやバグを除去したりするには、多くのリソースが必要になります。この場合は、次に説明する、グローバルに使用可能なスクリプト エディタでプラグインを使用する方法や、関数を定義する方法をお勧めします。
スクリプト エディタは、メニューの[編集] > [スクリプト エディタ]で使用できます。スクリプト エディタは、VRED シーンに直接アタッチされている Python ファイルと似ています。グローバルに使用可能な変数、関数、およびクラスをスクリプト エディタで定義できます。ここで記述したすべての Python コードは、バリアント セット、ターミナル、Web エンジンなどでも使用できます。したがって、スクリプト エディタはグローバルに使用できます。
エディタの下部には[実行]ボタンがあり、スクリプト エディタ内のすべてのコードを実行できます。ただし、[ファイル入出力]の基本設定にも設定が含まれています。VRED ファイルで、ファイルをロードするときにスクリプトとエディタを自動的に実行するかどうかを指定できます。既定の設定はオンであるため、スクリプトを自動実行しない場合は、このオプションをオフにします。
スクリプト エディタは、グローバルに定義された関数および変数に最適です。たとえば、現在のカメラ位置からビューポイントを作成する関数を使用できます。この関数は、任意のバリアント セットから呼び出すことも、リモートでトリガすることもできます。また、すべてのビューポイントを自動的にバッチ レンダリングして、定義可能なフォルダに保存する関数を使用できます。もちろん、スクリプト エディタで複雑なスクリプトを記述することもできます。
Python では、複数のモジュール、クラス、関数を 1 つのファイルに配置することができます。したがって、理論上は、この単一のスクリプト エディタに、グローバル関数、複数のツール、およびユーザ インタフェースを実装することができます。ただし、個人的な意見では、この作業は実に面倒であり、複雑すぎて、あまり維持しやすくありません。スクリプトのコードの行数が数百を超えている場合は、複数のスクリプト プラグインまたはモジュールに機能を分割する必要があります。
VRED の VR メニューの拡張に関するチュートリアル ビデオが用意されています。オートデスクでは、拡張された VR メニューに追加ツールを実装しています。このタスクを行う場合は、スクリプト エディタが適しています。
Python スクリプトが格納されているリポジトリがある場合は、Import 関数を使用してスクリプトを直接読み込むと便利な場合があります。この操作は、ファイルを開く場合と同じくらい簡単です。読み込まれたスクリプトは、スクリプト エディタの内容に追加されて、実行されます。ただし、ここで注意が必要になります。何らかの方法でシーンを操作するスクリプトがエディタ内に既に配置されている場合は、別のスクリプトを読み込むたびに、このスクリプトが再度実行されます。
Import 関数を使用すると、カスタム ユーザ インタフェースや、ファイルとして配置されている他の Python ツールを簡単に追加できます。「VR メニューの拡張」に関するチュートリアルでは、この方法を使用してシーンにカスタム VR ツールを読み込みます。
VRED で、完全に自動化されたレンダリング パイプラインを構築することもできます。シーンをロードして、イメージまたはムービーを自動的にレンダリングするために、-prepython
および -postpython
という 2 つのコマンド ライン オプションが用意されています。-prepython
を使用すると、シーンがロードされる前にスクリプトを実行でき、-postpython
を使用すると、シーンがロードされた後にスクリプトを実行できます。つまり、-prepython
を使用すると、モジュールやスクリプトの基本設定などから、シーンに依存していないスクリプトを実行できます。-postpython
を使用すると、スクリプト エディタで定義されたスクリプトを実行したり、プリセットとして保存されているレンダリング ジョブを開始したりできます。基本的に、VRED ターミナルに入力可能なすべての Python コマンドをセミコロンで区切って入力できます。
一般的な使用例としては、シーンをロードし、他の CAD モデルを読み込んで、すべてのビューポイントまたはムービーをレンダリングする場合などが挙げられます。この操作の後、VRED を終了して、別のファイルを使用することができます。自動レンダリングを行う場合は、いくつかのレンダリング プリセットを用意して、コマンド ラインから正しいレンダリング設定を選択できるようにすることをお勧めします。
よく使用する Python ツールと関数を追加する場合は、カスタム Python モジュールを使用することもできます。これらは、lib
フォルダの下の VRED アプリケーション フォルダ、および python
に追加されます。これらは他のモジュールと同様に構造化されていて、クラス、関数、および Python モジュールに保持できるほとんどあらゆるものを含めることができます。スクリプト エディタでスクリプトを作成する場合は、すべての VRED モジュールが自動的に読み込まれるわけではないことに注意する必要があります。つまり、すべての API v1 モジュールを明示的に読み込んでから、これらを使用する必要があります。ただし、API v2 モジュールは VRED によって挿入されるため、読み込む必要はありません。
それでも、複数のツール、Python 関数、クラスを一度に提供する場合は、モジュールが役立ちます。これらのモジュールは、VRED 設計者や開発者であれば誰でもインストールでき、すべてのモジュールで同じ Python スクリプト セットが共有されます。この方式の場合は、これらのスクリプトをリポジトリで管理することが可能になり、適切なコード品質を維持するのが大幅に簡単になるため、とても便利です。VRED ファイルまたはバリアント セットに Python スクリプトが保存されている場合は、すべてのスクリプトが複数のファイルに分散して格納されるため、この操作はそれほど簡単ではありません。
VRED インスタンスに機能を追加する場合の最も高度な方法は、スクリプト プラグインを使用することです。スクリプト プラグインは基本的に、ユーザ インタフェースに付属する VRED ツールであり、VRED のメニュー バーから使用することができます。プラグインは、1 つの小さなタスクを実行する数行のコードにすぎませんが、数百行のコードを記述して、VRED の操作方法や作業方法について全面的に変更することもできます。もちろん、スクリプト エディタでも同じ機能を実装できます。ただし、プラグインは VRED ファイルから独立していて、通常はサードパーティのコード エディタで記述されています。
独自のプラグインを開発する利点は、プラグインが VRED のメニュー バーに統合されていて、プラグインを他の設計者や開発者と簡単に共有できることです。プラグインは、シーンに含まれている他の Python コードとは別物です。そのため、ユーザが使用している他の Python スクリプトの状態がプラグインによって誤って変更されることはありません。
ここでは、スクリプト プラグインについて詳細に説明しません。これに関する完全なチュートリアルが用意されています。このチュートリアルでは、ユーザ インタフェースと一緒に独自のスクリプト プラグインを実装する方法を紹介します。確認してください。
ご覧いただいたとおり、シーンを変更する場合や、いくつかの単純な Python スクリプトや複雑な Python スクリプトを使用して VRED を操作する場合は、さまざまな方法を使用できます。これで、VRED での Python スクリプトの使用方法に関するあらゆる可能性について、理解を深めることができました。それぞれの問題には複数の解決策がありますが、目的を達成するための適正は Python インタフェースごとに異なります。
このビデオでは、これらの課題への対処方法に関するガイドラインを紹介しました。今日の説明はこれで終わりです。この後のチュートリアルでお会いするのを楽しみにしています。ご参加いただき、ありがとうございました。またお会いしましょう。
「 チュートリアル 3: VRED でスクリプトを使用する場合(一般的な使用事例) 」のビデオのために、3 つの Python サンプル スクリプトが用意されています。以下のファイルが含まれた ZIP ファイルをダウンロードするには、ここをクリックしてください。
REM Example 1
REM -prepython "print('Executed before file has loaded')" -postpython "print('Executed after file has loaded')"
REM Example 2
start "D:\Programme\Autodesk\VREDPro-<internalVersion>\bin\WIN64\VREDPro.exe" "C:\ProgramData\Autodesk\VREDPro-<internalVersion>\examples\Automotive_Genesis.vpb" -prepython "print('---');print('Executed before file has loaded')" -postpython "print('---');print('Executed after file has loaded')"
# Example 1.0
# Global function library
import time
from datetime import datetime
def logInfo(message):
now = datetime.now().time().strftime("%H:%M:%S.%f")
print(now, '[INFO]', message)
def logWarn(message):
now = datetime.now().time().strftime("%H:%M:%S.%f")
print(now, '[WARN]', message)
def createViewpointFromCamera():
now = datetime.now().time().strftime("%H:%M:%S.%f")
vrCameraService.createViewpoint("vp_{}".format(now))
def renderViewpoints():
viewpoints = vrCameraService.getAllViewpoints()
renderDirectory = vrFileDialog.getExistingDirectory(
"Select a render directory:",
vrFileIO.getFileIOBaseDir()
)
if not renderDirectory:
logWarn("No directory where to save the renderings!")
return
for viewpoint in viewpoints:
name = viewpoint.getName()
if name.startswith('vp_'):
vrRenderSettings.setRenderFilename("{}.jpg".format(name))
vrRenderSettings.startRenderToFile(False)
# Example 1
# Recreating material switches
print('--- Create Switch Materials ---')
allMaterials = getAllMaterials()
# get all materials which name starts with "switch"
switchMaterials = list(filter(lambda matPtr: matPtr.getName().startswith('switch'), allMaterials))
# iterate all switch materials
for switchMaterial in switchMaterials:
switchPtr = switchMaterial
switchName = switchPtr.getName()
print('Found switch: ' + str(switchName))
# extract material prefix
materialPrefix = '_'.join(switchName.split('_')[1:])
# Get all materials which name starts with the material prefix
childMaterials = list(filter(lambda matPtr: matPtr.getName().startswith(materialPrefix), allMaterials))
childMaterialNames = [x.getName() for x in childMaterials]
print('Found child materials: ' + ', '.join(childMaterialNames))
# Create new material switch
print('Create new material switch...')
newMaterialSwitch = createMaterial("SwitchMaterial")
newMaterialSwitch.setName(switchName)
# Add child materials to switch
for child in childMaterials:
newMaterialSwitch.addMaterial(child)
# swap old switch material with new switch material
print('Assign new material switch...')
nodes = switchPtr.getNodes()
for node in nodes:
node.setMaterial(newMaterialSwitch)
print('')
print('Finished!')
print('---')
# Example 2
# Calling global functions in the script editor
logInfo('This is an info message from a variant set.')
logWarn('This is a warning message from a variant set.')
createViewpointFromCamera()
renderViewpoints()