最終更新日:2010/12/13
最終更新時のNiVE2のバージョン: 2.0.1.0 (2010/12/04リリース)
更新履歴
2010/12/13
・「「エクスプレッション制御」のエフェクト群について」の項目を追加
・「エフェクトプリセットにはエフェクトエクスプレッションも含めることができます」の項目を追加
2010/12/08
・やっぱり要素追加型のプロパティも自由に追加・削除などができることが判明したので、
テキストレイヤーとシェイプレイヤー、および標準エフェクトのカスタムプロパティに関するサンプルコードを全面修正。
・「エクスプレッションの利用を想定したエフェクト等について」の項目を追加。
2010/12/06
・あれ・・・もしかしたら要素追加型のプロパティに要素追加したりできるかも・・・。
でもなんか無理やりな気がするので、サンプルコードの変更はちょっと保留。
2010/12/06
・ページを作成
概要
エクスプレッションは、「レイヤーやエフェクト等が持つプロパティ」を、「C#で書かれたプログラム」で制御する機能です。
通常、プロパティはキーフレームで制御しますが、プログラムで制御することでより多様な制御ができるようになります。
例として、「レイヤーの位置プロパティを制御して一定の水平往復運動を繰り返したい」というケースを考えます。
キーフレームだけでやろうとすると、往復のポイントごとにキーフレームを打っていく必要があります。
また、往復運動の幅やスピード、位置などを変える場合は最初からキーフレームを打ち直さなければなりません。
繰り返し回数が多いと、かなり面倒な作業になります。
しかし、エクスプレッションを使えば、レイヤーのエクスプレッションとして、
double amp = 100; // 振幅(ピクセル) double cycle = 1; // 1往復にかける時間(秒) VertexProperty pos = (VertexProperty)property.GetProperty(thisItem,"位置"); // 位置プロパティの取得 pos.X += amp * Math.Sin(Math.PI*2.0/cycle*time); // 位置のX座標の計算 property.SetProperty(thisItem,pos); // 位置プロパティの設定
という、たった5行のプログラムを書いておくだけで、水平往復運動を繰り返させることができます。
往復運動の幅やスピードの変更も、数値を書き換えるだけで簡単に行なうことができます。
このように、キーフレームだけで行なおうとすると手間がかかるような制御を簡単に実現したり、
複数のプロパティを同期させて制御するなど、工夫次第で応用範囲は広がります。
また、エフェクトプラグインの中には、エクスプレッションの利用を想定しているものもあります。
エクスプレッションを理解しておくと、それらのプラグインをより有効に利用することができるでしょう。
※重要!
基本的な説明については、NiVE2本体に
「エクスプレッション・オートメーションについて.pdf」
というマニュアルが同梱されているので、まずはそちらを参照して下さい。
※筆者は昔かじった基礎レベルの知識をもとに、かなりいい加減にプログラミングしてるので
ちゃんとしたプログラマーの方から見ると、とんでもなく変だったり回りくどい書き方をしてることがあるかも・・・。
目次
エクスプレッションで行なえること
プロパティの分類
エクスプレッションを記述する場所の分類と評価タイミング
記述フィールドについて
プロパティモニタについて
予め用意されている変数等についての補足説明
プロパティへのアクセス範囲
エクスプレッションに関するNiVE2本体の設定について
基本的なプロパティの型定義などについて
テキストレイヤーやシェイプレイヤー、標準エフェクトに関するカスタムプロパティについて
拡張プラグインの独自プロパティについて
「エクスプレッション制御」のエフェクト群について
エフェクトプリセットにはエフェクトエクスプレッションを含めることができます
基本的なサンプルコード
全ての自己プロパティ(propertyとthisItemから単純に取得できるプロパティ)をプロパティモニタに追加する
レイヤーエクスプレッションから、そのレイヤーの「不透明度」プロパティを取得・設定する
エフェクトエクスプレッションから、そのエフェクトが適用されているレイヤーの「位置」プロパティを取得・設定する
レイヤーエクスプレッションから、そのレイヤーに適用されている「塗り」エフェクトの「色」プロパティを取得・設定する
レイヤーエクスプレッションから、そのレイヤーの親レイヤーの「スケール」プロパティを取得・設定する
レイヤーエクスプレッションから、別のレイヤーの「回転」プロパティを取得・設定する
入力エクスプレッションから、レイヤープロパティやエフェクトプロパティを取得する(設定はできない)
レイヤーエクスプレッションから、別のコンポジションのレイヤープロパティやエフェクトプロパティを取得する(設定はできない)
テキストレイヤーの、カスタマイズされた入力プロパティ(セレクタやアニメータなど)を取得・設定する
シェイプレイヤーの、カスタマイズされた入力プロパティ(コンテンツ・グループ・シェイプなど)を取得・設定する
ガーベージマットエフェクトのマットポイントを操作する(標準エフェクトのカスタムプロパティの扱い)
エクスプレッションの利用を想定したエフェクトについて
エクスプレッション描画
カラー変換(エクスプレッション)
ハーフトーンもどき、ハーフトーンもどき(カラー)
テキスト(WPF)
実用的なサンプルコードはNiVE2 Wiki へ!
エクスプレッションで行なえるのは
●各種プロパティの取得や設定
●コンポジションやレイヤーなどに関する情報の取得
●各種ライブラリを用いた処理(C#でできることならほぼなんでもできる)
といった処理です。
これらを使って、
「思い通りの結果を得るためのプロパティ値を計算し、そのプロパティ値を設定することで描画等に干渉する。」
というのがエクスプレッションです。
注意すべきなのは、「エクスプレッションが直接NiVE2の描画に干渉できるわけではない」ということです。
あくまでも、「プロパティの設定」を通して処理結果を描画に反映させる必要があります。
エクスプレッションができるのはプロパティの設定までであり、そのプロパティを使って実際の描画処理などを行なうのは、
エフェクトやレンダラなどの仕事ということになります。
例えば、エクスプレッション内でGraphics.DrawLine()などを使って図形を描いたBitmapイメージを作成することはできますが、
そのイメージをレイヤー上に描画したいのであれば、
「エクスプレッションが作成したBitmapイメージを受け取るためのプロパティを持ち、
そのプロパティで受け取ったイメージをレイヤーに描画するエフェクトプラグイン」
が必要になります。
拡張プラグインの「エクスプレッション描画」は、これを実現しているエフェクトプラグインです。
エクスプレッションで扱うプロパティは、大きくわけて以下の3種類に分類されます。
(公式にこのように分類されているわけではありませんが、説明のために便宜的に分類しています。)
種類 | 説明 |
---|---|
入力プロパティ | 入力プラグインなどによって用意されたプロパティのこと。 例としては拡張プラグインの「Avisynth Input」で映像を読み込んだ場合の 「アルファ反映」プロパティが挙げられる。 また、テキストレイヤーの「テキスト」や、シェイプレイヤーの「シェイプ」、 ライトレイヤーの「ライト」に属するプロパティも、入力プロパティとなる。 |
レイヤープロパティ | レイヤーが持つプロパティ。 レイヤーの「トランスフォーム」や「レンダラ」、カメラの「オプション」などがこれにあたる。 |
エフェクトプロパティ | エフェクトが持つプロパティ。 |
エクスプレッションを記述する場所も、大きく以下の3つに分かれています。
(これも公式にこのように分類されているわけではありませんが、説明のために便宜的に分類しています。)
種類 | 説明 |
---|---|
入力エクスプレッション | 入力プロパティの記述フィールドに記述するエクスプレッション。 入力プロパティグループ(シェイプレイヤーの「シェイプ」等)のところで右クリックして 「エクスプレッションを使用する」にチェックを入れると記述フィールドが現れる。 入力エクスプレッションは、レイヤーエクスプレッションやエフェクトエクスプレッションとは 評価タイミングが異なる。(評価タイミングについては「エクスプレッションについて.pdf」を参照。) |
レイヤーエクスプレッション | レイヤーの記述フィールドに記述するエクスプレッション。 レイヤーを右クリックして「エクスプレッションを使用する」にチェックを入れると記述フィールドが現れる。 |
エフェクトエクスプレッション | エフェクトの記述フィールドに記述するエクスプレッション。 エフェクトを右クリックして「エクスプレッションを使用する」にチェックを入れると記述フィールドが現れる。 |
エクスプレッションは、NiVE2がフレームのレンダリングを行なう際に動的に評価されます。
かなり大雑把に処理の流れを書くと、
1.キーフレームなどによって暫定的なプロパティ値が決まる。
2.描画処理が行なわれる過程でエクスプレッションが評価され、最終的なプロパティ値が決定される。
最終的なプロパティ値に基づいて描画処理が行なわれる。
という感じになります。
詳しい評価タイミングについては「エクスプレッション・オートメーションについて.pdf」の説明を参照して下さい。
入力エクスプレッションのみ、評価タイミングが異なることに注意しましょう。
エクスプレッションの記述フィールドは、最初は表示されていません。
右クリックメニューで「エクスプレッションを使用する」を選択することで、表示されます。
入力プロパティについては、入力プロパティを束ねている部分を右クリックします。
レイヤーエクスプレッションはレイヤーを右クリック、エフェクトエクスプレッションはエフェクトを右クリックします。
記述フィールドは、「メイン」「メソッド・フィールド」「名前空間」「参照」「プロパティ」にわかれています。
「表示:」の部分をクリックすることでフィールドを選び、右側のレイヤーバー表示領域をクリックすると
レイヤーバー表示領域全体がエクスプレッション用の記述スペースになります。
それぞれのフィールドの意味については、NiVE2本体同梱の「エクスプレッション・オートメーションについて.pdf」を参照して下さい。
エクスプレッションでプロパティ値を変更しても、各プロパティの入力コントロール部の表示には反映されません。
例えば、レイヤーの不透明度の数値入力部を100にしてある状態でエクスプレッションから
不透明度のプロパティ値を50に設定しても、数値入力部の表示は100のままです。
エクスプレッションで設定したプロパティの実際の値の変化を見たい場合には、以下の手順でプロパティモニタを使います。
1.メイン部の記述で、あらかじめ用意されているMonitorというリスト型の変数に、見たいプロパティをAdd()で追加します。
2.記述フィールドの「表示:」で「プロパティ」を選ぶと、Monitorに追加したプロパティの一覧が下に表示されるので、
その中から見たいプロパティを選択すると、右側にそのプロパティの型や値が表示されます。
予め用意されている変数等についてはNiVE2本体に同梱されている
「エクスプレッション・オートメーションについて.pdf」
にも書かれていますが、ここではユーザが使えるものについてメモ代わりに少し補足しておきます。
用意されている変数の名前 | 補足説明 |
---|---|
property | ExpressionPropertyContainerの派生クラスのインスタンス。 入力エクスプレッションの場合はInputExpressionPropertyContainerクラス、 レイヤーまたはエフェクトエクスプレッションの場合はLayerExpressionPropertyContainerクラスとなる。 プロパティの取得や設定は、基本的にこれを通して行なう。 |
thisItem | エクスプレッションが所属するレイヤーやエフェクト。 入力エクスプレッションやレイヤーエクスプレッションの場合はLayerクラス。 エフェクトエクスプレッションならEffectクラス。 |
time | レイヤーのローカル時間。つまりレイヤーの開始位置から数えた時間。 コンポジション時間に変換するには、ILayerインタフェースのToWorldTime()を使う。 |
Monitor | PropertyBaseのリスト。 これにAdd()でプロパティを追加すると、プロパティモニタでプロパティの情報を見ることができる。 |
composition | IExpressionCompositionの配列。プロジェクトに存在するコンポジションの一覧。 |
各エクスプレッションの評価タイミングの違いなどがあるため、エクスプレッションからアクセスできる対象には制限があります。
以下の表に、各エクスプレッションから各プロパティへのアクセス可否を示します。
○・・・取得も設定も可能 △・・・取得のみ可能 ×・・・取得すら不可能
アクセス対象 | |||||||
自コンポジション | 他コンポジション | ||||||
自レイヤー | 他レイヤー | 他レイヤー | |||||
入力プロパティ | レイヤー・ エフェクトの プロパティ |
入力プロパティ | レイヤー・ エフェクトの プロパティ |
入力プロパティ | レイヤー・ エフェクトの プロパティ |
||
アクセス元 | 入力エクスプレッション | ○ | △ | × | △ | × | △ |
レイヤーエクスプレッション | × | ○ | × | ○ | × | △ | |
エフェクトエクスプレッション | × | ○ | × | ○ | × | △ |
エクスプレッションに関するNiVE2本体の設定には以下のようなものがあります。
それぞれの意味についてはNiVE2本体に同梱されている「操作説明.pdf」を参照して下さい。
■エクスプレッションを使用する
■エクスプレッションの除外検査をスキップする
■信頼済みアセンブリリストの登録
NumberPropertyやVertexPropertyなど、基本的なプロパティの定義については、
NiVE2 Wiki のプラグインページで公開されている、
「nive2-developplugin.pdf」(プラグイン開発について)
というマニュアルに掲載されていますのでそちらを参照しましょう。
テキストレイヤーやシェイプレイヤー、標準エフェクトに関するプロパティの定義については、
NiVE2本体に同梱されている
「カスタムプロパティ.pdf」(テキスト・シェイプレイヤー、標準付属のエフェクトのカスタムプロパティについて)
というマニュアルに掲載されているので、そちらを参照しましょう。
拡張プラグインでは、独自に定義されたプロパティが使われている場合があります。
エクスプレッションでの利用が想定されている場合はreadmeに扱い方が記載されていると思いますが、
記載がない場合はVisualStudioなどでDLLを調べるといった対処が必要なこともあります。
NiVE2の標準エフェクトには、「エクスプレッション制御」というカテゴリが存在します。
この中に含まれている「スライダ制御」などは、レイヤーに適用しても何の効果も与えないので、
「なんぞこれ?」と疑問に思っている人も多いと思います。
実はこれは名前どおり、エクスプレッションで利用するためのダミーエフェクトです。簡単に言うと、
「エクスプレッション内で使う変数の値をキーフレームで制御するためのもの」
と考えればよいと思います。
具体的な例として、レイヤーに円運動をさせるレイヤーエクスプレッションを考えます。
実際のコードは以下のようになります。
double speed = 90; // 1秒間に回転する角度 double hankei = 100; // 円運動の半径 VertexProperty pos = (VertexProperty)property.GetProperty(thisItem,"位置"); double rad = Math.PI/180.0*speed*time; pos.X += hankei*Math.Cos(rad); pos.Y += hankei*Math.Sin(rad); property.SetProperty(thisItem,pos);
ここで、「半径を時間的に変化させて螺旋運動をさせてみたい」と考えたとします。
エクスプレッション内に半径を変化させるための式を書いても良いのですが、もっと柔軟に制御したいところです。
そこで、エクスプレッション制御にある「スライダ制御」エフェクトの出番となります。
レイヤーにスライダ制御エフェクトを適用したうえで、右クリックメニューから「エフェクトのリネーム」を選び、
エフェクト名を"円運動の半径"に変更しておきます。
そのうえで、上記のレイヤーエクスプレッションを以下のように書き換えてみます。太字が変更部分です。
double speed = 90; // 1秒間に回転する角度 //------------------------------------------------------------------------ // 円運動の半径は、スライダ制御エフェクトのスライダプロパティから取得する //------------------------------------------------------------------------ double hankei = 100; // とりあえずデフォルト値は100にしておく foreach(IEffect e in ((ILayer)thisItem).GetEffect()){ if(e.ItemName == "円運動の半径"){ NumberProperty slider = (NumberProperty)property.GetProperty(e,"スライダ"); hankei = slider.DoubleValue; } } VertexProperty pos = (VertexProperty)property.GetProperty(thisItem,"位置"); double rad = Math.PI/180.0*speed*time; pos.X += hankei*Math.Cos(rad); pos.Y += hankei*Math.Sin(rad); property.SetProperty(thisItem,pos);
コメントにもあるように、半径の値は「"円運動の半径"と名前を変えたスライダ制御エフェクトのスライダプロパティ」から取得するようにしています。
あとは、適用してある「円運動の半径」エフェクトのスライダプロパティにキーフレームを打って0→300という感じで変化させれば、
レイヤーは半径を0から300に変化させつつ螺旋運動を行ないます。
キーフレームで半径の値を自由に変化させることができるので、わざわざエクスプレッション内で値や式を書き換えるよりも簡単です。
ここでは半径だけをダミーエフェクトから取得するようにしていますが、回転速度などもキーフレームで制御したいなら、
それ用のダミーエフェクトを適用して使えばよいということになります。
エクスプレッション制御のダミーエフェクトには、1つの数値を扱う「スライダ制御」の他にも
●色を扱う「カラー制御」
●論理値を扱う「チェックボックス制御」
●3つの値の組み合わせを扱う「ポイント制御」
●角度を扱う「角度制御」
がありますので、変数の定義によって使い分けることになります。
NiVE2には、エフェクトプリセットという機能があります。
これは、1つまたは複数のエフェクトの組み合わせを、キーフレームなどの設定情報も含めて
エフェクトプリセットファイル(*.nvep)として保存しておき、それを読み込んで再利用できるようにするという機能です。
よく使う色調補正系エフェクトなどの組み合わせを設定してエフェクトプリセットとして保存しておけば、
それを読み込むだけでエフェクトを再現できるので、毎回同じような設定をやり直す必要がなくなるわけですね。
このエフェクトプリセットには、設定したプロパティ値やキーフレームの情報が含まれますが、
エフェクトエクスプレッションを書いておけば、そのエクスプレッションもエフェクトプリセットに含まれます。
これを利用すれば、以下のようなエフェクトプリセットを作成することもできます。
●複数のエフェクトのプロパティをエクスプレッションで連動させて変化させるエフェクトプリセット
例) LightBurstと範囲変更を組み合わせ、LightBurstの範囲プロパティに連動して
その分だけ範囲変更エフェクトでROIを広げるエフェクトプリセット
●適用したレイヤーのプロパティを制御するエフェクトプリセット
例) 上で示した「スライダ制御を利用した螺旋運動のレイヤーエクスプレッション」を
以下のようにスライダ制御エフェクトのエフェクトエクスプレッション用に書き直し、
そのスライダ制御エフェクトをエフェクトプリセットとして保存すれば、
エフェクトプリセットの読み込みにより簡単に再利用できるようになります。
(わざわざ毎度レイヤーエクスプレッションを開いてコピペする必要がなくなる)
double speed = 90; // 1秒間に回転する角度 //------------------------------------------------------------------------ // 円運動の半径をスライダプロパティから取得する //------------------------------------------------------------------------ NumberProperty slider = (NumberProperty)property.GetProperty(thisItem,"スライダ"); double hankei = slider.DoubleValue; //------------------------------------------------------------------------ // このエフェクトが適用されているレイヤーの位置プロパティを取得・設定する //------------------------------------------------------------------------ VertexProperty pos = (VertexProperty)property.GetProperty(thisItem.ParentItem,"位置"); double rad = Math.PI/180.0*speed*time; pos.X += hankei*Math.Cos(rad); pos.Y += hankei*Math.Sin(rad); property.SetProperty(thisItem.ParentItem,pos);
現時点(NiVE v2.0.1)では、エクスプレッションを保存・読み込みする機能は用意されていませんので、
基本的には毎回エクスプレッションをコピペする必要がありますが、上の例のようにエフェクトエクスプレッションに書ける内容であれば、
エフェクトエクスプレッションとして記述してエフェクトプリセットとして保存しておけば、エクスプレッションを簡単に再利用することができて便利です。
プロパティへのアクセス方法など、基本的なサンプルコードを以下に示します。
●全ての自己プロパティ(propertyとthisItemから単純に取得できるプロパティ)をプロパティモニタに追加する
foreach(PropertyBase p in property.GetProperties(thisItem)){ Monitor.Add(p); }
●レイヤーエクスプレッションから、そのレイヤーの「不透明度」プロパティを取得・設定する
// 自己プロパティの取得・設定。 // これはレイヤーエクスプレッションの例だが、入力エクスプレッションやエフェクトエクスプレッションでも同様。 // 不透明度プロパティの取得 NumberProperty futoumei = (NumberProperty)property.GetProperty(thisItem,"不透明度"); // 不透明度プロパティの設定 futoumei.DoubleValue = 50; // 不透明度を50に設定してみる // GetProperty()ではコピーされたプロパティが返されるので、 // 変更を反映させるためには必ずSetProperty()を実行する必要がある。 property.SetProperty(thisItem,futoumei);
●エフェクトエクスプレッションから、そのエフェクトが適用されているレイヤーの「位置」プロパティを取得・設定する
/ エフェクトエクスプレッションでは // thisItem・・・エフェクトのこと // thisItem.ParentItem・・・エフェクトが適用されているレイヤーのこと // となる。 // thisItem.ParentItemを指定して位置プロパティを取得すれば // 「エフェクトが適用されているレイヤー」の位置プロパティが取得できる。 VertexProperty pos = (VertexProperty)property.GetProperty(thisItem.ParentItem,"位置"); // timeを利用してX方向に1秒間あたり100ピクセル移動するようにしてみる。 pos.X = 100*time; // 設定でもthisItem.ParentItemを利用する。 property.SetProperty(thisItem.ParentItem,pos);
●レイヤーエクスプレッションから、そのレイヤーに適用されている「塗り」エフェクトの「色」プロパティを取得・設定する。
// ILayerインタフェースのGetEffect()を利用してエフェクトの一覧を取得し、 // 対象のエフェクトのプロパティに対して操作を行なう。 IEffect[] effectArray = ((ILayer)thisItem).GetEffect(); foreach(IEffect e in effectArray){ if(e.ItemName == "塗り"){ ColorProperty col = (ColorProperty)property.GetProperty(e,"色"); col.Color = Color.FromArgb(255,255,255,0); property.SetProperty(e,col); break; } }
●レイヤーエクスプレッションから、そのレイヤーの親レイヤーの「スケール」プロパティを取得・設定する
// デバッグ用の文字列を入れるためのStringPropertyを作ってモニタする。 StringProperty dbg = new StringProperty("デバッグ",""); Monitor.Add(dbg); // 親子関係を設定している場合は、 // ●IExpressionLayerインタフェースのParentExpressionLayer // ●ILayerインタフェースのParentLayer // のどちらかを使って親レイヤーを取得することができる。 IExpressionLayer pLayer = ((IExpressionLayer)thisItem).ParentExpressionLayer; if(pLayer == null){ dbg.Text = "親設定なし"; } else{ dbg.Text = "親レイヤーの名前は[" + pLayer.ItemName + "]"; VertexProperty scale = (VertexProperty)property.GetProperty(pLayer,"スケール"); scale.VertexValue = new Vertex(50,50,50); property.SetProperty(pLayer,scale); }
●レイヤーエクスプレッションから、別のレイヤーの「回転」プロパティを取得・設定する
// レイヤーエクスプレッションの場合、thisItem.ParentItemは、所属するコンポジションを表す。 // ICompositionインタフェースのGetLayer()を利用してレイヤー一覧を取得し、対象のレイヤーのプロパティを操作する。 ILayer[] layerArray = ((IComposition)thisItem.ParentItem).GetLayer(); foreach(ILayer layer in layerArray){ if(layer.ItemName == "おっすオラ別のレイヤー"){ RadianProperty zRot = (RadianProperty)property.GetProperty(layer,"Z回転"); zRot.Angle = 45; property.SetProperty(layer,zRot); break; } }
●入力エクスプレッションから、レイヤープロパティやエフェクトプロパティを取得する(設定はできない)
// 入力エクスプレッションは、エフェクトやレイヤーエクスプレッションとは // 評価タイミングが異なるので、レイヤーやエフェクトのプロパティについては取得しかできない。 // また、取得にもひと手間かける必要がある。 // デバッグ用の文字列を入れるためのStringPropertyを作ってモニタする。 StringProperty dbg = new StringProperty("デバッグ",""); Monitor.Add(dbg); // とりあえず自分が所属するコンポジションを取得する。 // ICompositionではなくIExpressionCompositionインターフェースを使う。 IExpressionComposition comp = (IExpressionComposition)thisItem.ParentItem; // 通常のプロパティアクセスで使うためのproperty変数は、入力エクスプレッションでは入力プロパティしか扱えない。 // そのためまずはExecuteExpression()を使ってコンポジション内のレイヤーエクスプレッションや // エフェクトエクスプレッションを評価し、評価後のレイヤープロパティやエフェクトプロパティを扱うための // ExpressionPropertyContainerを取得する。 // 引数の時間はコンポジション時間で与えるべきなので、ToWorldTime()で変換している。 ExpressionPropertyContainer lpCon = comp.ExecuteExpression(((ILayer)thisItem).ToWorldTime(time)); // 取得したExpressionPropertyContainerを使って、自分のレイヤーのレイヤープロパティにアクセスする。 NumberProperty futoumei = (NumberProperty)lpCon.GetProperty(thisItem,"不透明度"); if(futoumei == null){ dbg.Text = "null"; } else{ dbg.Text = futoumei.DoubleValue.ToString(); } // 自分以外のレイヤーの情報を取得したいのであればGetLayer()を使って対象レイヤーを取得し、 // lpConを使ってそのレイヤーにアクセスすればよい。ここでは省略。
●レイヤーエクスプレッションから、別のコンポジションのレイヤープロパティやエフェクトプロパティを取得する(設定はできない)
StringProperty dbg = new StringProperty("デバッグ",""); Monitor.Add(dbg); IExpressionComposition targetComp = null; ExpressionPropertyContainer targetPcon = null; ILayer targetLayer = null; // composition変数にはプロジェクト内のコンポジション一覧が入っている。 // その中から目的のコンポジションを名前をキーにして取得する。 foreach(IExpressionComposition comp in composition){ if(comp.ItemName == "部品コンポジ"){ targetComp = comp; break; } } // 見つかったら次の処理へ if(targetComp == null){ dbg.Text = "対象コンポジションがありません"; } else{ // 対象コンポジ内にある「部品レイヤー」を取得 foreach(ILayer layer in ((IComposition)targetComp).GetLayer()){ if(layer.ItemName == "部品レイヤー"){ targetLayer = layer; break; } } // 見つかったら次の処理へ if(targetLayer == null){ dbg.Text = "対象レイヤーがありません"; } else{ // 対象コンポジのエクスプレッションの評価を行い、そのコンポジションの // レイヤープロパティを扱うExpressionPropertyContainerを取得する。 targetPcon = targetComp.ExecuteExpression(((ILayer)thisItem).ToWorldTime(time)); // 対象コンポジ用のExpressionPropertyContainerを使い、 // 対象レイヤーの位置プロパティを取得する。 VertexProperty pos = (VertexProperty)targetPcon.GetProperty(targetLayer,"位置"); dbg.Text = pos.ToString(); } }
●テキストレイヤーの、カスタマイズされた入力プロパティ(セレクタやアニメータなど)を取得・設定する
//------------------------------------------------------------------------- // エクスプレッションでセレクタやアニメータを追加してみる //------------------------------------------------------------------------- //------------------------------------------------------------------------- // 前提 // ●テキストレイヤーの入力エクスプレッションで記述 // ●入力エクスプレッションの「参照」で、 // NiVE2.Core.Text.dll // を追加すること。 // ●入力エクスプレッションの「名前空間」で、 // NiVE2.Core.Text // を追加すること。 //------------------------------------------------------------------------- StringProperty dbg = new StringProperty("デバッグ","---dbgLog Start---"); Monitor.Add(dbg); //------------------------------------------------------------------------- // ソーステキストや色、配置などのプロパティは簡単に操作できる。 //------------------------------------------------------------------------- // 配置を中央揃えにする SelectableProperty haichi = (SelectableProperty)property.GetProperty(thisItem,"配置"); haichi.Selected = haichi.Items.IndexOf("中央揃え"); property.SetProperty(thisItem,haichi); //------------------------------------------------------------------------- // 「テキストアニメータ」プロパティはTextAddablePropertyクラス。 // 要素を追加していくタイプのプロパティのため、扱いがやや複雑。 // // ※TextAddablePropertyや関連クラスの詳細についてはNiVE2本体に同梱されている // 「カスタムプロパティについて.pdf」 // を参照すること。 //------------------------------------------------------------------------- // 「テキストアニメータ」プロパティを取得 TextAddableProperty textAnimator = (TextAddableProperty)property.GetProperty(thisItem,"テキストアニメータ"); //------------------------------------------------------------------------- // 「テキストアニメータ」には「セレクタ」を追加していくようになっている。 // 「セレクタ」はTextSelectorPropertyクラス。 // 新しいセレクタを生成し、開始の値を設定する。 //------------------------------------------------------------------------ // 追加するセレクタを生成する。 // 追加要素はCreateProperty()を使って生成する。 TextSelectorProperty selector = (TextSelectorProperty)textAnimator.CreateProperty(typeof(TextSelectorProperty)); // 生成しただけではStartなどのメンバーデータがnullのままなので // InitializeDefaultProperty()で初期化してやる必要がある。 selector.InitializeDefaultProperty(); // セレクタの「開始」の設定 // (5秒かけて0→100に変化) selector.Start.DoubleValue = 20*time; //------------------------------------------------------------------------ // 「セレクタ」の「アニメータ」には色々なアニメータを追加していくようになっている。 // 「アニメータ」はTextAnimatorAddablePropertyクラス。 // // ★セレクタのAnimator.PropertiesはInitializeDefaultProperty()の後でも // nullのままなので、アニメータを追加しない場合でも要素数ゼロで // 生成しておかないとNullReferenceExceptionが発生する。 // (まあアニメータを追加しない場合なんてないけど・・・。) // // とりあえずここでは「位置」と「スケール」のアニメータを追加してみる。 //------------------------------------------------------------------------ //------------------------------------------------------------------------ // アニメータ2つを格納するための配列を生成しPropertiesに入れておく。 // アニメータはTextPropertyBaseからの派生クラスなので、その配列を作っている。 //------------------------------------------------------------------------ TextAnimatorAddableProperty animator = selector.Animator; animator.Properties = new TextPropertyBase[2]; //------------------------------------------------------------------------ // 「位置」アニメータの追加 // 「位置」アニメータはPositionAnimatorPropertySetクラス。 //------------------------------------------------------------------------ // 追加要素はCreateProperty()を使って生成する PositionAnimatorPropertySet posAnim = (PositionAnimatorPropertySet)animator.CreateProperty(typeof(PositionAnimatorPropertySet)); // 生成したら必ず初期化 posAnim.InitializeDefaultProperty(); // 値の設定 posAnim.Position.VertexValue = new Vertex(0,-200,0); // セレクタの1つ目のアニメータとして追加 animator.Properties[0] = posAnim; //------------------------------------------------------------------------ // 「スケール」アニメータの追加 // 「スケール」アニメータはScaleAnimatorPropertySetクラス。 //------------------------------------------------------------------------ // 追加要素はCreateProperty()を使って生成する ScaleAnimatorPropertySet scaleAnim = (ScaleAnimatorPropertySet)animator.CreateProperty(typeof(ScaleAnimatorPropertySet)); // 生成したら必ず初期化 scaleAnim.InitializeDefaultProperty(); // 値の設定 scaleAnim.Scale.VertexValue = new Vertex(0,0,0); // セレクタの2つ目のアニメータとして追加 animator.Properties[1] = scaleAnim; //------------------------------------------------------------------------ // セレクタを「テキストアニメータ」プロパティに追加する //------------------------------------------------------------------------ //------------------------------------------------------------------------ // 新しいセレクタを既存のセレクタ群の末尾に追加する場合 //------------------------------------------------------------------------ /* // 要素数を1増やしたセレクタ格納用配列を生成 int len = textAnimator.Properties.Length; TextSelectorProperty[] newArray = new TextSelectorProperty[len+1]; // 既存のセレクタをコピー Array.Copy(textAnimator.Properties, newArray, len); // 生成したセレクタを末尾に追加 newArray[len] = selector; //「テキストアニメータ」のPropertiesの置き換え textAnimator.Properties = newArray; */ //------------------------------------------------------------------------ // 既存セレクタを無視して強制上書きしてしまう場合 //------------------------------------------------------------------------ // 新しいセレクタを格納する配列を生成して //「テキストアニメータ」のPropertiesを置き換える textAnimator.Properties = new TextSelectorProperty[1]; // 生成したセレクタを格納する。 textAnimator.Properties[0] = selector; //------------------------------------------------------------------------ // 最後に「テキストアニメータ」プロパティの設定を忘れずに //------------------------------------------------------------------------ property.SetProperty(thisItem,textAnimator); Monitor.Add(textAnimator);
●シェイプレイヤーの、カスタマイズされた入力プロパティ(コンテンツ・グループ・シェイプなど)を取得・設定する。
//------------------------------------------------------------------------- // エクスプレッションでグループ、シェイプ、線を追加してみる //------------------------------------------------------------------------- //------------------------------------------------------------------------- // 前提 // ●シェイプレイヤーの入力エクスプレッションで記述 // ●入力エクスプレッションの「参照」で、 // NiVE2.Core.Shape.dll // を追加すること。 // ●入力エクスプレッションの「名前空間」で、 // NiVE2.Core.Shape // を追加すること。 //------------------------------------------------------------------------- StringProperty dbg = new StringProperty("デバッグ","---dbgLog Start---"); Monitor.Add(dbg); //------------------------------------------------------------------------- // 「コンテンツ」はShapeContentsAddablePropertyクラス。 // 要素を追加していくタイプのプロパティのため、扱いがやや複雑。 // // ※ShapeContentsAddablePropertyや関連クラスの詳細についてはNiVE2本体に同梱されている // 「カスタムプロパティについて.pdf」 // を参照すること。 //------------------------------------------------------------------------- ShapeContentsAddableProperty contents = (ShapeContentsAddableProperty)property.GetProperty(thisItem,"コンテンツ"); //------------------------------------------------------------------------- // 「コンテンツ」には「グループ」を追加していくようになっている。 // 「グループ」はShapeGroupPropertySetクラス。 //------------------------------------------------------------------------- // 追加する「グループ」を生成する。 // 追加要素はCreateProperty()を使って生成する。 ShapeGroupPropertySet group = (ShapeGroupPropertySet)contents.CreateProperty(typeof(ShapeGroupPropertySet)); // 生成しただけではメンバーデータがnullのままなので // InitializeDefaultProperty()で初期化してやる必要がある。 group.InitializeDefaultProperty(); //------------------------------------------------------------------------- // 「グループ」を表すShapeGroupPropertySetクラスは // ShapeGroupAddableProperty型のGroup変数を持ち、そこに対して // グループ・シェイプ・塗り・線・トランスフォーム // といった要素を追加していくようになっている。 // // グループの中にグループを入れ子で追加できるようになっているので // ちょっとややこしい。 // // ★グループのGroup.PropertiesはInitializeDefaultProperty()の後でも // nullのままなので、シェイププロパティを追加しない場合でも要素数ゼロで // 生成しておかないとNullReferenceExceptionが発生する。 // (まあシェイププロパティを追加しない場合なんてないけど・・・。) // // ここではグループに「シェイプ」と「線」の2つを追加してみる。 //------------------------------------------------------------------------- //------------------------------------------------------------------------ // シェイププロパティ2つを格納するための配列を生成しPropertiesに入れておく。 // シェイププロパティはShapePropertySetBaseからの派生クラスなので、その配列を作っている。 //------------------------------------------------------------------------ ShapeGroupAddableProperty groupList = group.Group; groupList.Properties = new ShapePropertySetBase[2]; //------------------------------------------------------------------------- // 「シェイプ」はShapePointPropertySetクラス。 //------------------------------------------------------------------------- // 追加要素はCreateProperty()を使って生成する ShapePointPropertySet shape = (ShapePointPropertySet)groupList.CreateProperty(typeof(ShapePointPropertySet)); // 生成したら必ず初期化 shape.InitializeDefaultProperty(); // 始点の設定 shape.StartPoint.VertexValue = new Vertex(0,0,0); //---------------------------------------------------------------- // 「シェイプ」は「ポイントリスト」を持っており、そこに対して // リニア・ベジェ // のポイントを追加していくようになっている。 // 「ポイントリスト」はShapePointAddablePropertyクラス。 // // ここではリニア1つとベジェ1つを追加してみる。 //---------------------------------------------------------------- //---------------------------------------------------------------- // ポイント2つを格納するための配列を生成しPropertiesに入れておく。 //---------------------------------------------------------------- ShapePointAddableProperty pointList = shape.PointList; pointList.Properties = new ShapePropertySetBase[2]; //---------------------------------------------------------------- // 扇のような形状をベースに想定して内角と半径をもとに計算。 // 内角を時間的に変化させている。 // このへんは適当にやったのであまり気にせずに・・・。 //---------------------------------------------------------------- double kakudo = 300*time; double hankei = 200; double rad = Math.PI/180.0*kakudo/2.0; double rad2 = rad - rad*2.0/3.0; double pointX = shape.StartPoint.X + hankei*Math.Cos(rad); double pointY = shape.StartPoint.Y + hankei*Math.Sin(rad); double ctrlX = shape.StartPoint.X + hankei*Math.Cos(rad2); double ctrlY = shape.StartPoint.Y + hankei*Math.Sin(rad2); //---------------------------------------------------------------- // まずは「リニア」を追加 //---------------------------------------------------------------- // 追加要素はCreateProperty()を使って生成する LinearPointPropertySet linear = (LinearPointPropertySet)pointList.CreateProperty(typeof(LinearPointPropertySet)); // 生成したら必ず初期化 linear.InitializeDefaultProperty(); // 値の設定 linear.Point.VertexValue = new Vertex(pointX,pointY,0); // ポイントリストの1つ目の要素として追加 pointList.Properties[0] = linear; //---------------------------------------------------------------- // 次にベジェを追加 //---------------------------------------------------------------- // 追加要素はCreateProperty()を使って生成する BezierPointPropertySet bezier = (BezierPointPropertySet)pointList.CreateProperty(typeof(BezierPointPropertySet)); // 生成したら必ず初期化 bezier.InitializeDefaultProperty(); // 値の設定。 bezier.Point.VertexValue = new Vertex(pointX,-pointY,0); bezier.ControlPoint1.VertexValue = new Vertex(ctrlX,ctrlY,0); bezier.ControlPoint2.VertexValue = new Vertex(ctrlX,-ctrlY,0); // ポイントリストの2つ目の要素として追加 pointList.Properties[1] = bezier; //---------------------------------------------------------------- // ポイントの設定が終わったのでグループの1つ目の要素として追加 //---------------------------------------------------------------- groupList.Properties[0] = shape; //---------------------------------------------------------------- // 「線」はLinePropertySetクラス //---------------------------------------------------------------- // 追加要素はCreateProperty()を使って生成する LinePropertySet line = (LinePropertySet)groupList.CreateProperty(typeof(LinePropertySet)); // 生成したら必ず初期化 line.InitializeDefaultProperty(); // 値の設定 line.Width.Int32Value=10; line.Color.Color = Color.FromArgb(255,255,255,0); //---------------------------------------------------------------- // 設定が終わったのでグループの2つ目の要素として追加 //---------------------------------------------------------------- groupList.Properties[1] = line; //------------------------------------------------------------------------- // グループの設定が終わったので「コンテンツ」にグループを追加する。 //------------------------------------------------------------------------- //------------------------------------------------------------------------ // 新しいグループを既存のグループ群の末尾に追加する場合 //------------------------------------------------------------------------ /* // 要素数を1増やしたグループ格納用配列を生成 int len = contents.Properties.Length; ShapeGroupPropertySet[] newArray = new ShapeGroupPropertySet[len+1]; // 既存のセレクタをコピー Array.Copy(contents.Properties, newArray, len); // 生成したグループを末尾に追加 newArray[len] = group; //「コンテンツ」のPropertiesの置き換え contents.Properties = newArray; */ //------------------------------------------------------------------------ // 既存のグループを無視して強制上書きしてしまう場合 //------------------------------------------------------------------------ // 新しいグループを格納する配列を生成して //「コンテンツ」のPropertiesを置き換える contents.Properties = new ShapeGroupPropertySet[1]; // 生成したグループを格納する。 contents.Properties[0] = group; //------------------------------------------------------------------------ // 最後に「コンテンツ」プロパティをSetPropertyするのを忘れないようにする。 //------------------------------------------------------------------------ property.SetProperty(thisItem,contents); Monitor.Add(contents);
●ガーベージマットエフェクトのマットポイントを操作する(標準エフェクトのカスタムプロパティの扱い)
//------------------------------------------------------------------------- // ガーベージマットエフェクトでマットポイントを追加する //------------------------------------------------------------------------- //------------------------------------------------------------------------- // 前提 // ●ガーベージマットのエフェクトエクスプレッションで記述 // ●エフェクトエクスプレッションの「参照」で、 // Plugins/NiVE2.PresetPlugin.dll // を追加すること。 // ●エフェクトエクスプレッションの「名前空間」で、 // NiVE2.PresetPlugin.Utils // を追加すること。 //------------------------------------------------------------------------- StringProperty dbg = new StringProperty("デバッグ","---dbgLog Start---"); Monitor.Add(dbg); //------------------------------------------------------------------------- // 「マットポイント」はGarbageMatPointAddablePropertyクラス。 // 要素を追加していくタイプのプロパティのため、扱いがやや複雑。 // // ※GarbageMatPointAddablePropertyや関連クラスの詳細についてはNiVE2本体に同梱されている // 「カスタムプロパティについて.pdf」 // を参照すること。 //------------------------------------------------------------------------- GarbageMatPointAddableProperty matPoint = (GarbageMatPointAddableProperty)property.GetProperty(thisItem,"マットポイント"); //------------------------------------------------------------------------- // 「マットポイント」には「ポイント」を追加していくようになっている。 // 「ポイント」はGarbageMatPointPropertySetクラス。 // // ポイントを3つ追加し、正三角形の形で回転するように値を設定する。 //------------------------------------------------------------------------- //------------------------------------------------------------------------- // レイヤーの中心座標を求める。 // GetImageBounds()は低画質モードの場合は画質にあわせたサイズを返すので、 // 低画質モード時でも表示がおかしくならないよう、ResolutionRateで割っている。 //------------------------------------------------------------------------- double res = ((ILayer)thisItem.ParentItem).ResolutionRate; RectangleF rect = ((ILayer)thisItem.ParentItem).GetImageBounds(time); double centerX = rect.Width/res/2.0; double centerY = rect.Height/res/2.0; //dbg.Text += "\nRsolutionRate: " + res; //dbg.Text += "\nGetImageBounds(): " + rect; // 半径と角速度 double hankei = 100; double kakudo = 180; // 1秒間あたりの回転角度。単位は度。 //------------------------------------------------------------------------- // ポイントを3つ格納するための配列を作ってPropertiesに設定。 // Propertiesを上書きしているので、既存のポイントがあっても無視される。 //------------------------------------------------------------------------- matPoint.Properties = new GarbageMatPointPropertySet[3]; //------------------------------------------------------------------------- // ポイントを3つ生成して値を設定し、マットポイントに追加する //------------------------------------------------------------------------- GarbageMatPointPropertySet point = null; double rad = 0; for(int i=0; (i<3 && i<matPoint.Properties.Length); i++){ // 追加するポイントをCreateProperty()で生成する。 point = (GarbageMatPointPropertySet)matPoint.CreateProperty(typeof(GarbageMatPointPropertySet)); // 生成した後は必ず初期化する point.InitializeDefaultProperty(); // 値を設定する rad = Math.PI/180.0*kakudo*time+Math.PI*2/3.0*i; point.Position.X = centerX + hankei*Math.Cos(rad); point.Position.Y = centerY + hankei*Math.Sin(rad); // マットポイントに追加 matPoint.Properties[i] = point; } //------------------------------------------------------------------------- // 値を変えた後は「マットポイント」プロパティのSetPropertyを忘れずに。 //------------------------------------------------------------------------- property.SetProperty(thisItem,matPoint); Monitor.Add(matPoint);
一部のエフェクトでは、エクスプレッションの利用を想定して、専用の隠しプロパティなどが用意されていることがあります。
ここではそういったものについてのサンプルコードや簡単な説明などを載せています。
基本的に拡張プラグインのreadmeやサンプルなどから転載しています。
バージョンアップで変わることもありますし、必ず最新のreadmeを参照するようにしましょう。
●エクスプレッション描画
エクスプレッション描画では、隠しプロパティとして「Delegate」が定義されており、
デリゲートを記述することでイメージの描画を行なわせることができます。
◎例1.BitmapDrawのデリゲートで線の描画を行なう。(v1.0.0のreadmeより転載)
//------------------------------------------------------------------------ // 以下の設定が必要 // //【名前空間】 // Sh5ExpressionDrawPlugin //【参照】 // Plugins\Sh5ExpressionDrawPlugin.dll //------------------------------------------------------------------------ //------------------------------------------------------------------------ // Bitmapを使いたい場合:(線を引いたり、円を描いたり) //------------------------------------------------------------------------ DelegateProperty d = (DelegateProperty)property.GetProperty(thisItem, "Delegate"); d.BitmapDraw = delegate(Bitmap b, Roi roi, double resolutionRate) { using (Graphics g = Graphics.FromImage(b)) { // ROI調整 g.TranslateTransform(roi.ImageX, roi.ImageY); // 解像度調整 g.ScaleTransform((float)resolutionRate, (float)resolutionRate); // ここ以降で描画する // アンチエイリアスをかける g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; // 線を引く g.DrawLine(Pens.White, 0, 0, 512, 384); } }; property.SetProperty(thisItem, d);
◎例2.NBitmapDrawのデリゲートでARGB値を調整する。(v1.0.0のreadmeより転載)
//------------------------------------------------------------------------ // 以下の設定が必要 // //【名前空間】 // Sh5ExpressionDrawPlugin //【参照】 // Plugins\Sh5ExpressionDrawPlugin.dll //------------------------------------------------------------------------ //------------------------------------------------------------------------ // NBitmapを使いたい場合:(ARGB値をいじりたい場合とか) //------------------------------------------------------------------------ DelegateProperty d = (DelegateProperty)property.GetProperty(thisItem, "Delegate"); IExpressionItem thisLayer = thisItem.ParentItem; // 全然関係ないけどワールドタイムの求め方 double wtime = ((ILayer)thisLayer).ToWorldTime(time); d.NBitmapDraw = delegate(NBitmap b, Roi roi, double resolutionRate) { int size = (int)b.DataSize; byte[] data = b.GetData(); for (int i = 0; i < (int)size;i+=4) { // 元イメージはありでないと意味がありません // アルファ値を半分にする data[i+3] = (byte)(data[i+3]/2); // 赤の値を3/4にする data[i+2] = (byte)(data[i+2]*3/4); // 緑の値を2/3にする data[i+1] = (byte)(data[i+1]*2/3); // 青の値を7/8にする data[i+0] = (byte)(data[i+0]*7/8); } }; property.SetProperty(thisItem, d);
●カラー変換(エクスプレッション)
カラー変換(エクスプレッション)では、「ConvertFunc」プロパティのFunctionにデリゲートを記述することで、
イメージのピクセルの色変換を行なうことができます。
◎例1.色の反転を行なう。(v0.2のreadmeから転載)
//------------------------------------------------------------------------ // 以下の設定が必要。同梱の"ColorChangeExpressionTemplate.nvep"を使うと楽。 // //【名前空間】 // ColorChangeExpression //【参照】 // Plugins\ColorChangeExpression.dll //------------------------------------------------------------------------ //------------------------------------------------------------------------ // ConvertFuncProperty の取得 //------------------------------------------------------------------------ ConvertFuncProperty p = (ConvertFuncProperty)property.GetProperty(thisItem, "ConvertFunc"); //------------------------------------------------------------------------ // デリゲートの設定 // パラメータ // r,g,b,a : 処理対象ピクセルの値です。これを書き換えることにより変換を行います。 // モードがRGBの場合、ピクセルのRGBA値となります。範囲は0〜255です。 // モードがHLSの場合、ピクセルのRGBをHLSに変換した値になります。 // r ⇒ H 0〜360, g ⇒ L 0〜1000, b ⇒ S 0〜1000, aはRGBの場合と同じ // x,y : ピクセルの座標です。左上が原点(0,0)です。 //------------------------------------------------------------------------ p.Function = delegate(ref int r, ref int g, ref int b, ref int a, int x, int y) { // 反転 r = 255-r; g = 255-g; b = 255-b; return; }; property.SetProperty(thisItem, p);
●ハーフトーンもどき、ハーフトーンもどき(カラー)
「ハーフトーンもどき」、および「ハーフトーンもどき(カラー)」では、「ThresholdFunc」というプロパティのFunctionに
デリゲートを記述することで、ハーフトーン化処理時のパターンを自分で作成することができます。
「パターン」プロパティで「エクスプレッション」を指定すると、エクスプレッションで作成したパターンが使用されます。
◎例 (v0.3bのreadmeより転載)
//------------------------------------------------------------------------ // 以下の設定が必要。 // //【名前空間】 // nml.NiVE2.Plugin //【参照】 // Plugins\PseudoHalfTone.dll //------------------------------------------------------------------------ //------------------------------------------------------------------------ // ThresholdFuncProperty の取得 //------------------------------------------------------------------------ ThresholdFuncProperty p = (ThresholdFuncProperty)property.GetProperty(thisItem, "ThresholdFunc"); //------------------------------------------------------------------------ // デリゲートの設定 // 設定するデリゲートの型は // double ThresholdFunc(int x, int y, int size) // です。 // // パターンは内部的には、size×sizeの配列で表されています。 // このパターンの作成時に、下記引数でデリゲートの呼び出しを行います。 // x : 0〜size-1 // y : 0〜size-1 // size : 「サイズ」×「オーバーサンプリング」 // // デリゲートからの戻り値が、パターンの値となります。 // (ハーフトーン化処理の際に、値の大きい位置から、埋められていくイメージ) //------------------------------------------------------------------------ p.Function = delegate(int x, int y, int size) { int xx = (x * 2) - (size - 1); int yy = (y * 2) - (size - 1); return Math.Max(Math.Abs(xx), Math.Abs(yy)); }; property.SetProperty(thisItem, p);
●テキスト(WPF)
テキスト(WPF)では、隠しプロパティ「delegate」「variable」にデリゲートを記述することで、
文字の簡易アニメーションや複雑な整形、タグ内での変数の使用などが可能になっています。
//------------------------------------------------------------------------ // 以下の設定が必要。 // //【名前空間】 // NiveSh5TextRangePlugin //【参照】 // Plugins\plugintextrange2.dll //------------------------------------------------------------------------ // 内容については長くなるのでreadmeを参照して下さい。 // サンプルとして、 // ・カラオケタグ付きの文字を表示する際に、文字が不透明度を上げながら出現し、 // その後やや小さくなっていくという簡易アニメーション // ・特定の文字の配置を変えることで縦書きっぽく整形する // ・整形タグ内のスケール値に変数名を記述しておき、その変数の値をエクスプレッションで設定する // というコードが記載されています。
NiVE2 Wiki に、サンプルコードのページが出来ました。
自由に投稿できるようになっているので、実用的なエクスプレッションを書いたら是非投稿してみましょう。