ティラノスクリプトの3D その5:3d_show
今回は、既存のタグ [3d_show] に付いて話します。
理由は、次の新規タグを理解するに必要な為と、このタグは私なりに修正が必要することになる点と、今のタグには、使い方を間違うとシナリオが止まってしまうバグがあることが理由です。
まずは、本家を整形したコードを以下にお見せします。
tyrano.plugin.kag.tag["3d_show"] = {
vital: ["name"],
pm: {
name: "",
group: "default",
group_uuid: "",
time: "500",
scale: "",
pos: "",
rot: "",
force_sprite: "false",
wait: "true",
visible: "true",
},
start: function (pm) {
var three = this.kag.tmp.three;
if (0 != $.checkThreeModel(pm.name)) {
var model = this.kag.tmp.three.models[pm.name];
if ("template" === model.pm._type) {
var models = this.kag.tmp.three.models;
let group_name = model.pm.name;
for (let key in models) {
var _model = models[key];
_model.pm.group && _model.pm.group == group_name && _model.show();
}
}
(model.model.isSprite || "true" == pm.force_sprite) &&
(pm.group = "sprite");
three.groups[pm.group] || (three.groups[pm.group] = []);
three.groups[pm.group].push(model.model);
model.model.name = pm.name;
if ("" != pm.group_uuid) {
three.scene.getObjectByProperty("uuid", pm.group_uuid).add(model.model);
} else three.scene.add(model.model);
var options = { duration: parseInt(pm.time) };
if ("" != pm.pos) {
let pos = $.three_pos(pm.pos);
model.setPosition(pos.x, pos.y, pos.z);
}
if ("" != pm.scale) {
let scale = $.three_pos(pm.scale);
model.setScale(scale.x, scale.y, scale.z);
}
if ("" != pm.rot) {
let rot = $.three_pos(pm.rot);
model.setRotation(rot.x, rot.y, rot.z);
}
if ("true" == pm.visible)
if ("0" == pm.time) {
console.log(model);
model.show();
this.kag.ftag.nextOrder();
} else if ("true" == pm.wait)
model.fade("in", options, () => {
this.kag.ftag.nextOrder();
});
else {
model.fade("in", options);
this.kag.ftag.nextOrder();
}
else {
model.setVisible(!1);
this.kag.ftag.nextOrder();
}
}
},
};
tyrano.plugin.kag.tag["3d_hide"] = {
vital: ["name"],
pm: { name: "", time: "500", next: "true", wait: "true" },
start: function (pm) {
if (0 != $.checkThreeModel(pm.name)) {
var three = this.kag.tmp.three,
options = { duration: parseInt(pm.time) },
model = this.kag.tmp.three.models[pm.name];
if ("true" == pm.wait)
model.fade("out", options, (_model) => {
this.kag.ftag.nextOrder();
three.scene.remove(_model);
});
else {
model.fade("out", options, (_model) => {
three.scene.remove(_model);
});
this.kag.ftag.nextOrder();
}
}
},
};
tyrano.plugin.kag.tag["3d_hide_all"] = {
vital: [],
pm: { time: "500", wait: "true" },
start: function (pm) {
var three = this.kag.tmp.three,
options = { duration: parseInt(pm.time) },
models = this.kag.tmp.three.models,
cnt_fade = 0,
fin_fade = 0;
for (let key in models)
if ("camera" != key) {
cnt_fade++;
if ("true" == pm.wait)
models[key].fade("out", options, (_model) => {
three.scene.remove(_model);
fin_fade++;
cnt_fade == fin_fade && this.kag.ftag.nextOrder();
});
else {
models[key].fade("out", options, (_model) => {
three.scene.remove(_model);
fin_fade++;
});
this.kag.ftag.nextOrder();
}
}
0 == cnt_fade && this.kag.ftag.nextOrder();
},
};
序に、3d_hide と 3d_hide_all も添付しています。
コードを見ると、結構未公開のパラメータがあります。この中で考慮が必要なものは、group と group_uuid です。
それに、show なのに、visible というパラメータが余分にあるのは、誤解を招きます。不要な気がします。
話を元に戻して、この group は、3Dオブジェクトを纏めて一括して制御できるようにする three.js の本来の機能に関するものでしょう。three.js のオブジェクト(Object3D)は、他のオブジェクトの親になる機能と、その逆の子になる機能を持っています。それらは、自由な階層にでき、さらに group という、ただ入れ物用のオブジェクトもあります。ティラノスクリプトの3Dには、このグループ化する機能を将来追加する予定のようです。これ自身は、three.js の機能なので、それを指定するタグを用意すれば何の問題もありません。
しかし、ティラノスクリプトとしては、タグで実行した結果をセーブした後ロードしたときに以前のシーンを再現できる必要があります。これを、実現するため、全ての3dオブジェクトを前回述べた ThreeModel というクラスに格納しています。となると、その ThreeModel 中に、各オブジェクトの親子関係を再構築できる情報が必要になり、かつ、それを再構築する処理をそれが必要な全てのタグ(親子関係を指定する可能性のある全てのタグ)に必要になります。それで、この 3d_show と、ThreeModel の中でモデルの表示をどのように管理しているかしらべました。お分かりのように、オブジェクトを表示させるには、そのオブジェクトの visual 属性を true にすることと、そのオブジェクトをシーンにaddする必要があります。ただ、別のオブジェクトの子になっているオブジェクトは、このシーンにaddする必要はありません。ですから、この 3d_show の中でどう記述されているか見てみましょう。
すると、それに関わる所は、32行~34行の部分のみです。ここだけで、親のオブジェクトにaddするかシーンにaddするか判断しています。
しかし、この判断には group_uuid のみが関わっています。しかしシナリオライターにこのパラメータの値を指定するのは無理です。一方、group というパラメータは、別に three.groups というグループ特性のあるオブジェクトの格納配列に登録するだけにしか使ってない風です。ただ、親のオブジェクトは、group 属性のオブジェクトだけでなく、どんなオブジェクトににも格納できますので、このような管理の仕方はちょっと疑問です。
ティラノスクリプトでは、オブジェクトを非表示にすると、オブジェクトのvisible 属性を false にするだけでなく、シーンからも削除する方針のようです。ただ、親子関係に付いては、他の隠しタグを見る限りは、親子関係を指定した時点で構築しているようです。
最後に、コード中にある if (0 != $.checkThreeModel(pm.name)) は、指定した名前が、ちゃんと登録したものかしらべてます。見つかった場合は、問題なくタグが実行されますが、見つからなかった場合は、単にリターンしているだけです。ここでは、this.kag.ftag.nextOrder(); を実行しなければ次のタグに制御が写りません。一応、それらを考慮して、上記の三つのタグを以下のように、修正して、プラグインに加えます。
TYRANO.kag.tag["3d_show"] = {
vital: ["name"],
pm: {
name: "",
group: "default",
group_uuid: "",
time: "500",
scale: "",
pos: "",
rot: "",
force_sprite: "false",
wait: "true",
},
start: function (pm) {
let three = this.kag.tmp.three;
if (0 != $.checkThreeModel(pm.name)) {
let model = this.kag.tmp.three.models[pm.name];
if( model.pm.parent === undefined ) model.pm.parent = "";
if ("template" === model.pm._type) {
var models = this.kag.tmp.three.models;
let group_name = model.pm.name;
for (let key in models) {
var _model = models[key];
_model.pm.group && _model.pm.group == group_name && _model.show();
}
}
(model.model.isSprite || "true" == pm.force_sprite) &&
(pm.group = "sprite");
three.groups[pm.group] || (three.groups[pm.group] = []);
three.groups[pm.group].push(model.model);
model.model.name = pm.name;
// 以下、対象のオブジェクトのパラメータに、親の名前が無い場合にシーンに追加するように修正.
if ("" != pm.group_uuid) {
three.scene.getObjectByProperty("uuid", pm.group_uuid).add(model.model);
} else if( model.pm.parent == "") three.scene.add(model.model);
var options = { duration: parseInt(pm.time) };
if ("" != pm.pos) {
let pos = $.three_pos(pm.pos);
model.setPosition(pos.x, pos.y, pos.z);
}
if ("" != pm.scale) {
let scale = $.three_pos(pm.scale);
model.setScale(scale.x, scale.y, scale.z);
}
if ("" != pm.rot) {
let rot = $.three_pos(pm.rot);
model.setRotation(rot.x, rot.y, rot.z);
}
if( model.model.isLight == true ){
model.model.visible = true ;
}
if ("0" == pm.time || 0 == pm.time ) {
console.log(model);
model.show();
this.kag.ftag.nextOrder();
} else if ("true" == pm.wait){
model.fade("in", options, () => {
//model.show();
this.kag.ftag.nextOrder();
});
}
else {
model.fade("in", options);
this.kag.ftag.nextOrder();
}
}
else {
this.kag.ftag.nextOrder();
}
}
};
TYRANO.kag.ftag.master_tag["3d_show"] = TYRANO.kag.tag["3d_show"];
TYRANO.kag.ftag.master_tag["3d_show"].kag = TYRANO.kag ;
// 3d_hide の修正版
// 未指定の_model if文の{}の _model を削除
// 対象のモデルが親を持つ場合(pm.parentに名前があるで判断)シーンにremoveしないようにする。
TYRANO.kag.tag["3d_hide"] = {
vital: ["name"],
pm: { name: "", time: "500", next: "true", wait: "true" },
start: function (pm) {
if (0 != $.checkThreeModel(pm.name)) {
let three = this.kag.tmp.three,
options = { duration: parseInt(pm.time) },
model = this.kag.tmp.three.models[pm.name];
if( model.pm.parent === undefined ) model.pm.parent = "";
if ("true" == pm.wait) {
model.fade("out", options, (_model) => {
if( model.pm.parent == "") three.scene.remove(_model);
if ( model.model.isLight == true ) model.model.visible = false;
this.kag.ftag.nextOrder();
});
} else {
model.fade("out", options, (_model) => {
if( model.pm.parent == "") three.scene.remove(_model);
if ( model.model.isLight == true ) model.model.visible = false;
});
this.kag.ftag.nextOrder();
}
} else {
this.kag.ftag.nextOrder();
}
}
};
TYRANO.kag.ftag.master_tag["3d_hide"] = TYRANO.kag.tag["3d_hide"];
TYRANO.kag.ftag.master_tag["3d_hide"].kag = TYRANO.kag ;
// 3d_hide_all の修正版
// 未指定の_model if文の{}の _model を削除
// 対象のモデルが親を持つ場合(pm.parentに名前があるで判断)シーンにremoveしないようにする。
TYRANO.kag.tag["3d_hide_all"] = {
vital: [],
pm: { time: "500", wait: "true" },
start: function (pm) {
let three = this.kag.tmp.three,
options = { duration: parseInt(pm.time) },
models = this.kag.tmp.three.models;
if( pm.wait =="true"){
// waitする場合は、最後のオブジェクトを隠すのが終わった時点で、nextOrder()を実行する
let cnt_fade = 0,
fin_fade = 0;
for (let key in models){
if ("camera" != key) {
cnt_fade++;
models[key].fade("out", options, (_model) => {
if( model.pm.parent === undefined ) model.pm.parent = "";
if( model.pm.parent == "") three.scene.remove(_model);
if ( model.model.isLight == true ) model.model.visible = false;
fin_fade++;
cnt_fade == fin_fade && this.kag.ftag.nextOrder();
});
}
};
}
else{
// wait しない場合は、ループ一回りしたら、次のタグに飛ぶ。
for (let key in models){
if ("camera" != key) {
models[key].fade("out", options, (_model) => {
if( model.pm.parent === undefined ) model.pm.parent = "";
if( model.pm.parent == "") three.scene.remove(_model);
if ( model.model.isLight == true ) model.model.visible = false;
});
}
}
this.kag.ftag.nextOrder();
}
}
};
TYRANO.kag.ftag.master_tag["3d_hide_all"] = TYRANO.kag.tag["3d_hide_all"];
TYRANO.kag.ftag.master_tag["3d_hide_all"].kag = TYRANO.kag ;
基本的には、ThreeModel 内の生成時のパラメターpmの中の parent パラメータが空でない場合は、そのオブジェクトをシーンに add したり、 remove したりしないという点と、バグと思しきところを修正しました。ただし、全ての機能確認は終わってませんので、最終版ではありません。
****3月5日時点の修正***
で、光源の場合は、ThreeModelクラス内の fade() メソッドが、ちょっとうまく動かないのでコードを修正しました。