Shade3D 公式

プラグインでのシーン内の形状の相互参照法に付いて


#1

今まで、あまり気にせずにつかっていたのですが、今回「頂点モーフプラグイン」等のプラグインで、
形状間の相互参照を頻繁に使っていたのですが、どうも挙動が気になるので質問させて貰います。
今のところ私は、形状間の相互参照用に、
shape_class のset_related_shape(),get_related_shapes()
や、
stream_interfaceでのread_shape(),write_shape()を使っていましたが、
これらの切り口では、形状の位置をブラウザで変更すると、参照が切れてしまうようです。
また、登録している、形状の直前に形状を生成すると、その生成した形状が、登録している形状に変わってしまうようです。
これって仕様なんでしょうか?少なくともShade13は、同じ挙動でした。
貴社のIK機構などでは、幾ら位置関係を変えても参照は、切れないようですが、別の方法なのでしょうか。
上記の関数は、内部的には、形状のオーディナルで管理し、取り出す時にshape_classに直して返すように見えます。
ハンドルでは、シーンの保存時に保持されないし、shape_classのuuid
は、シーンを開く度に異なるし、名前では重複してしまう可能性があります。他の方法としては、オリジナルのuuid
を各形状に与えて、それで参照しあう手もありますが、あまりに大変な気がします。
何か良い方法があれば、お教えください。


#2

masa様

開発よりの回答をお伝えさせていただきます。

stream_interface の read_shape, write_shape は、
ブラウザの階層構造から形状のポインタを読み書きするため、
ブラウザの階層構造を変更すると参照が切れてしまいます。
そのため、read_shape, write_shape はブラウザの階層構造が変化しない、
シーンを開いた直後とシーン保存の直前に使用します。

shape_class の set_related_shape, get_related_shapes は、
形状に直接書き込まれるため、階層構造が変化しても保持されますので、
set_related_shape, get_related_shapes のほうを使用してください。
uuid は、プラグインIDのように、他のプラグインと重複しない値を定数で指定しています。

また、コードサンプルも合わせてお伝えさせていただきます。
ただし、コンパイルしての検証はしておりませんので、その点ご了承くださいますようお願いいたします。

const sx:::uuid_class MYPLUGIN_UUID("XXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX");

// 例:shape_class の set_related_shape, get_related_shapes の使用例

sxsdk::shape_class &target = scene->get_active_shape();
shape.set_related_shape(MYPLUGIN_UUID, &target); // MYPLUGIN_UUIDをキーとして、shape形状にtarget形状を関連付ける.

// ...

const int n = shape.get_related_shapes(MYPLUGIN_UUID, 0); // MYPLUGIN_UUIDをキーとして、関連付けした形状数を取得.
if (0 < n) {
std::unique_ptr<sxsdk::shape_class*[]> targets(new sxsdk::shape_class*[n]); // 形状のアドレスを格納する器(shape_class*[])を確保.
shape.get_related_shapes(MYPLUGIN_UUID, targets.get()); // 器に、形状のアドレス(shape_class*)を格納する.
// ...
// スコープを抜けるとき、器(shape_class*[])は解放される、格納された形状のアドレス(shape_class*)は解放しない.
}

// 例:stream_interface の read_shape, write_shape 使用例

virtual void scene_opened (bool& b, sxsdk::scene_interface* scene, void* aux) {
compointer<sxsdk::stream_interface> stream(scene->get_attribute_stream(MYPLUGIN_UUID));
	if (stream) {
		sxsdk::shape_class *p = 0;
		stream->read_shape(scene, p);
		if (p) {
			scene->message(p->get_name());
		}
	}
}

virtual void scene_closed (bool& b, sxsdk::scene_interface* scene, void* aux) {
	compointer<sxsdk::stream_interface> stream(scene->get_attribute_stream(MYPLUGIN_UUID));
	if (stream == 0) {
		stream = scene->create_attribute_stream(MYPLUGIN_UUID);
	}
	if (stream) {
		sxsdk::shape_class &shape = scene->active_shape();		
		stream->write_shape(&shape);
	}
}

#3

回答有り難うございます。
stream_interfaceのread_shape(),write_shape()の件了承しました。
ただ、related_shape系の関数を使った場合でも、参照切れが起こるようです。
このフォーラムの「頂点モーフ」プラグインの設計時は、最初related_shape系の関数で実装していましたが、
2個目以降での追加がうまくいいきませんでしたので、現時点では、ブラウザ上の並びで管理することに変更しました。
そのときの挙動は、以下の通りです。
1.ポリゴン形状Aの直下にカスタムジョイントBを作り、第一のモーフを実装、この時ポリゴンAに対して、カスタムジョイントBを
related_shapeとして登録、
2.ポリゴン形状Aに新たなモーフを作り、2個目のモーフを登録して、カスタムジョイントCをカスタムジョイントBの前に作る。
このとき、ポリゴンAのrelated_shapeを調べて、Cを追加しようとすると、登録数は1、ポリゴン形状Aの相手の形状は、
カスタムジョイントCと変わってしまっていたのです。そのため、追加モーフは動くのに、最初のモーフは、動かなくなってました。
どうも、related_shape系だけでも問題有りそうなので、色々対策を考えてみます。


#4

masa様

開発部からの回答となります。

B.set_related_shape(UUID, A); # B に A を関連付ける
C.set_related_shape(UUID, A); # C に A を関連付ける

C.get_related_shape(UUID); # C に関連付けられた形状数

のようなコードになっていないでしょうか?
この場合、登録数が1となります。

A.get_related_shape(UUID); # A に関連付けられた形状数

であれば、登録数が2となるはずです。

以下のような流れになります。
set_related_shapeのA,Bは逆にしても結果は同じになります。

B に A を関連付ける
B.set_related_shape(UUID, A);

              B[UUID].insert(A) -> B[UUID] has [A]
              A[UUID].insert(B) -> A[UUID] has [B]

その結果
A に関連付けられた形状数は1
A.get_related_shape(UUID)
A[UUID] has [B]

B に関連付けられた形状数は1
B.get_related_shape(UUID)
B[UUID] has [A]

さらに、C に A を関連付ける
C.set_related_shape(UUID, A);

              C[UUID].insert(A) -> C[UUID] has [A]
              A[UUID].insert(C) -> A[UUID] has [B,C]

その結果
A に関連付けられた形状数は2
A.get_related_shape(UUID)
A[UUID] has [B, C]

B に関連付けられた形状数は1
B.get_related_shape(UUID)
B[UUID] has [A]

C に関連付けられた形状数は1
C.get_related_shape(UUID)
C[UUID] has [A]


#5

回答有り難うございます。
成る程、related_shapeには、登録の方向があるという訳ですね。
その観点で、もう一度作り直してみます。
結果は、週明けにでも報告します。


#6

ご指摘の様な指定方法で再記述した結果、正しく動作することが分かりました。
どうも有り難うございました。
これで要約公開出来そうです。
相互参照している自作プラグインをもう一度確認していきたいと思います。