/// 選択ボーンに対応するウェイトを加算する。 /// returns: ウェイトを変更したか public bool Execute() { foreach (MqoSkinWeight skin_weight in vertex.skin_weights) { SkinWeightCommand skin_weight_command = new SkinWeightCommand(skin_weight); this.skin_weight_commands.Add(skin_weight_command); } //処理前の値を記憶する。 { int nskin_weight = 0; foreach (MqoSkinWeight skin_weight in vertex.skin_weights) { this.skin_weight_commands[nskin_weight].old_attr.bone = skin_weight.bone; this.skin_weight_commands[nskin_weight].old_attr.weight = skin_weight.weight; nskin_weight++; } } bool updated = false; //選択ボーンに対応するウェイトを検索する。 MqoSkinWeight selected_skin_weight = null; foreach (MqoSkinWeight skin_weight in vertex.skin_weights) { if (skin_weight.bone == selected_node) { selected_skin_weight = skin_weight; break; } } bool prepare_bone = false; switch (weight_op) { case WeightOperation.Gain: prepare_bone = weight > 0; break; case WeightOperation.Assign: prepare_bone = weight > 0; break; } //選択ボーンに対応するウェイトがなければ、最小値を持つウェイトを置き換える。 if (selected_skin_weight == null && prepare_bone) { TSONode bone = selected_node; { selected_skin_weight = vertex.skin_weights[3]; //前提: vertex.skin_weights の要素数は 4 かつ並び順はウェイト値の降順 selected_skin_weight.bone = bone; selected_skin_weight.weight = 0.0f; } } //選択ボーンに対応するウェイトを加算する。 if (selected_skin_weight != null) { updated = true; float w0 = selected_skin_weight.weight; //変更前の対象ウェイト値 float m0 = 1.0f - w0; //変更前の残りウェイト値 float w1; //変更後の対象ウェイト値 switch (weight_op) { case WeightOperation.Gain: w1 = w0 + weight; break; case WeightOperation.Reduce: w1 = w0 - weight; break; case WeightOperation.Assign: w1 = weight; break; default: w1 = w0; break; } //clamp 0.0f .. 1.0f if (w1 > 1.0f) { w1 = 1.0f; } if (w1 < 0.0f) { w1 = 0.0f; } float d1 = w1 - w0; //実際の加算値 float m1 = 0.0f; //減算後の残りウェイト値 if (m0 != 0) { //残りウェイトを減算する。 foreach (MqoSkinWeight skin_weight in vertex.skin_weights) { if (skin_weight == selected_skin_weight) { continue; } float w2 = skin_weight.weight - skin_weight.weight * d1 / m0; if (w2 < 0.001f) { w2 = 0.0f;//微小ウェイトは捨てる。 } skin_weight.weight = w2; m1 += w2; } } selected_skin_weight.weight = 1.0f - m1; Array.Sort(vertex.skin_weights); } #if false { int nskin_weight = 0; foreach (MqoSkinWeight skin_weight in vertex.skin_weights) { Console.WriteLine("i:{0} bone:{1} w:{2}", nskin_weight, skin_weight.bone.Name, skin_weight.weight); nskin_weight++; } Console.WriteLine(); } #endif //処理後の値を記憶する。 { int nskin_weight = 0; foreach (MqoSkinWeight skin_weight in vertex.skin_weights) { this.skin_weight_commands[nskin_weight].new_attr.bone = skin_weight.bone; this.skin_weight_commands[nskin_weight].new_attr.weight = skin_weight.weight; nskin_weight++; } } return(updated); }
/// スキンウェイト操作を生成します。 public SkinWeightCommand(MqoSkinWeight skin_weight) { this.skin_weight = skin_weight; }