検索はキーワードに基づいています。
例:「手順」
自然言語で検索しないでください
例:「新しいプロシージャを作成するにはどうすればよいですか?」
OpScriptパフォーマンスの改善
Lua Garbage Collectorを理解する
Luaでは、メモリはスタックまたはヒープに割り当てることができます。ヒープに割り当てられたオブジェクトまたはメモリは、Luaのガベージコレクターによって回収されます。したがって、ガベージコレクターが実行されている場合、Luaコードは前方に進むことができないため、ガベージコレクターを実行する頻度を減らすか、ガベージコレクターが収集するガベージの量を減らすと、OpScriptsのパフォーマンスが向上します。
次のLuaコンストラクトは、悪くはありませんが、ガベージコレクション中に後でクリーンアップする必要がある新しいオブジェクトを作成します。これらのコンストラクトがループ内で使用される場合、特に注意する必要があります。
- String_one..string_two -文字列の連結または任意の文字列作成関数により、新しいオブジェクトが作成される可能性があります。Luaの文字列は一意であるため、最初に文字列が他の場所で作成されているかどうかを確認します。
- { … } -テーブルコンストラクターが実行されるたびに、新しいテーブルが作成されます。
- function() ... end -関数ステートメントを実行すると、クロージャーが作成されます。これをn回の繰り返しのループ内で実行すると、n個のクロージャーが作成されます。
注意: 詳細についてはlua-users.org。
ループ内の「..」を避ける
Luaガベージコレクターの理解の具体例として、この推奨事項では、便利な略記法によりOpScriptsで一般的に使用される文字列連結演算子「..」の使用を検討します。
例として、L-System記述を作成するために使用される次のコードを考えてください。
local結果= "" for i = 1、#inputStr do local char = inputStr:sub(i、i) local ruleStr = rulesTable [char] if ruleStr then 結果=結果..ruleStr else 結果= result..char end end return結果 |
result
タイトループで追加されます。便利ではありますが、これにより、文字列が大量に割り当てられ、パフォーマンスが低下します。上記のコードは、以下に示すようにループが完了した後にのみ、すべての連結を処理するように書き直すことができます。
ローカルbuf = {} for i = 1、#inputStr do local char = inputStr:sub(i、i) ローカルruleStr = rulesTable [char] if ruleStr then buf [#buf + 1] = ruleStr else buf [#buf + 1] = char end end return table.concat(buf) |
大規模の一部として上記の例を実行するKatanaシーンファイルは、次の表に示すように、この関数のシーン処理時間を約2.5倍短縮しました。
文字列メソッド |
時間 |
「..」演算子 |
7.011秒 |
Table.concat() |
2.681s |
高価なOpScriptを置き換えるカスタムC ++ Opの作成を検討してください
LuaとOpScript APIは非常に便利で多用途ですが、シーンのトラバース時間の大部分を占めるOpScriptsは、カスタムC ++ Opsとして適しています。
具体的な例として、次のOpScriptを考えてみましょう。このOpScriptは、ターゲットボックスの位置、向き、およびスケールを一様なボックス内でランダムに配置します。
ローカルハッシュ= ExpressionMath.stablehash(Interface.GetOutputName())) math.randomseed(hash)
local薄暗い= 10 local s = 0.15
local sx = s *(1 + 0.5 * math.random()) local sy = s *(1 + 0.5 * math.random()) local sz = s *(1 + 0.5 * math.random())
local tx = 2 * dim *(math.random()-0.5) local ty = dim * math.random()+ sy local tz = 2 * dim *(math.random()-0.5)
local ax = math.random() local ay = math.random() local az = math.random() local axis = Imath.V3d(ax、ay、az):normalize() local角度= 360 * math.random()
local translate = Imath.V3d(tx、ty、tz) local rotate = Imath.V4d(angle、axis.x、axis.y、axis.z) localスケール= Imath.V3d(sx、sy、sz)
Interface.SetAttr( "xform.group0.translate"、 DoubleAttribute(translate:toTable()、3)) Interface.SetAttr( "xform.group0.rotate"、 DoubleAttribute(rotate:toTable()、4)) Interface.SetAttr( "xform.group0.scale"、 DoubleAttribute(scale:toTable()、3)) |
(そのようなOpScriptはもちろん工夫されていますが、ジオメトリを配置するためにランダム性を明確に定義された分布に置き換えることを想像できます。)
このOpScriptは、次のC ++ Opとして書き換えられます。
#include <FnAttribute / FnAttribute.h> #include <FnGeolib / op / FnGeolibOp.h> #include <FnGeolibServices / FnExpressionMath.h> #include <FnGeolibServices / FnGeolibCookInterfaceUtilsService.h> #include <FnPluginSystem / FnPlugin.h>
#include <cstdlib>
inline double getRandom() { return (double)rand()/( double )RAND_MAX; } struct DistributeGeometryOp: public Foundry :: Katana :: GeolibOp { static void setup(Foundry :: Katana :: GeolibSetupInterface&interface) { interface.setThreading(Foundry :: Katana :: GeolibSetupInterface :: ThreadModeConcurrent); } static void cook(Foundry :: Katana :: GeolibCookInterface&interface) { srand(FnGeolibServices :: FnExpressionMath :: stablehash(interface.getOutputName())); double dim = 10.0; double s = 0.15f; double sx = s *(1.0 + 0.5f * getRandom()); double sy = s *(1.0 + 0.5f * getRandom()); double sz = s *(1.0 + 0.5f * getRandom());
double tx = 2.0f * dim *(getRandom()-0.5f); double ty = dim * getRandom()+ sy; double tz = 2.0f * dim *(getRandom()-0.5f);
double ax = getRandom(); double ay = getRandom(); double az = getRandom();
double axisLen = sqrt(ax * ax + ay * ay + az * az); ax / = axisLen; ay / = axisLen; az / = axisLen;
double角度= 360.0 * getRandom();
double translate [] = {tx、ty、tz}; double rotate [] = {angle、ax、ay、az}; double scale [] = {sx、sy、sz}; interface.setAttr( 「Xform.group0.translate」、 FnAttribute :: DoubleAttribute(translate、3、3)); interface.setAttr( 「Xform.group0.rotate」、 FnAttribute :: DoubleAttribute(rotate、4、4)); interface.setAttr( 「Xform.group0.scale」、 FnAttribute :: DoubleAttribute(scale、3、3)); } }; DEFINE_GEOLIBOP_PLUGIN(DistributeGeometryOp); void registerPlugins() { REGISTER_PLUGIN(DistributeGeometryOp、 "DistributeGeometryOp"、0、1); } |
異なるランダム分布まで、これらのOpsは同じシーンを生成します。ただし、C ++バージョンは約3.2倍の速度で実行されます。10,000個のジオメトリックプリミティブの配置に使用される場合、Opsは次のリソースを使用します。
Op |
CPU時間 |
使用メモリ |
OpScript |
0.989秒 |
54.24 MiB |
C ++ Op |
0.310秒 |
53.67 MiB |
この場合、メモリ使用量は似ています。ただし、OpScriptが多数の小さなオブジェクトを割り当てて解放している場合、C ++に変換すると、Luaガベージコレクションに費やす時間も節約されます。
申し訳ありませんが、これは役に立ちませんでした
なぜこれが役に立たなかったのですか? (当てはまるもの全てをご確認ください)
ご意見をいただきありがとうございます。
探しているものが見つからない場合、またはワークフローに関する質問がある場合は、お試しくださいファウンドリサポート。
学習コンテンツを改善する方法についてご意見がある場合は、下のボタンを使用してドキュメントチームにメールしてください。
フィードバックをお寄せいただきありがとうございます。