投稿記事

DazScriptの記事 (3)

柱前堂 2024/05/04 22:20

マウスピースぶっとびアッパー

DAZ で人体を動かして、アッパーでダウンする流れを作ってみました。
ぶっといボディブローで体がくの字に折れて、顎を差し出しちゃったところに渾身の一発が……というシチュです。

ロープ越しに。

攻め手視点。


Timeline タブを動かして各時点でのポーズを指定すれば、間のフレームはいい感じに補完してくれるので思ったよりは手間がかかりませんでした。
今回はお試しということで、1秒おきにポーズ指定をしています。マウスピースだけ前回のスクリプトを使って飛ばしています。
ただし見ての通り、動きごとの速度の考慮とか、そもそものポーズの善し悪しとか、作品としての完成度には課題が山積みです。

カメラの位置やレンズ設定も時間とともに変化させられますが、テクスチャを切り替えるのは出来ませんでした。マウスピースが落ちたところに染みを増やすとかやりたかったんですが……。
どうしてもやりたいなら、その時点で別々の動画にして後で繋げれば出来そうです。

今回はマウスピースだけスクリプトを使いましたが、簡単な幾何で計算できる部分はDAZの補完に頼るよりもっとスクリプトを使った方が良さそうです。
とくに腰が動くときにうまいこと計算させたいです。DAZフィギュアの仕様上、腰の位置を絶対座標で指定し、そこから伸びる足の角度を指定することで足の位置が決まります。従って、腰を上げ下げするときは腰の位置と足の角度をうまく連動させないと、キャンバスから足が離れたり埋まったりしてしまいます。物理的には足首や膝といった下から上へ動きが決まるはずなので、下側の角度を変化させながら足裏の位置が動かないように腰の位置を逆算する計算をしたいところです。

柱前堂 2024/03/02 21:51

アッパーぶっとびマウスピース

Daz アニメ再び、アッパーでぶっとぶマウスピースをやってみました。

やったこと

1フレームずつ速さと位置を更新してマウスピースに適用しています。
y軸がキャンバスの高さを下回ったら、反発係数0.3でy軸運動量を逆向きにします。

バウンドするごとの最高到達点は、前回の高さ×(反発係数の二乗)になるので、一回のバウンドでおおよそ前回の1割の高さになります。
口から射出された直後はキャンバスから3mくらいの高さまで届いているので、一回目のバウンド後は30cmくらいまで跳ねる計算です。

一回ごとの軌道は放物線なので速さと位置を保持しなくても毎フレームの位置を計算できるのですが、何バウンド目かを保持して軌道を表現する二次関数を切り替えないといけないので、1フレームずつ演算した方が楽かと思います。
後述する今後の課題にも対応しやすそうです。

今後の課題

まず飛ぶ範囲に対してマウスピースが小さいので、カメラ位置が難しいですね。動かすなりカットを入れて動画を分けるなりすればいいのかな……。

y軸方向に小刻みに跳ね続けているのもちょっと不気味です。実際には空気抵抗とか唾液の粘性とか反発係数の変化とかで一定以下の速度になったら跳ねなくなると思うんですが、そういう処理を入れるべきですね。

x, z軸方向も一定速度を保っているのでちょっと元気すぎます。これも空気抵抗を適当に入れるといいのかしら。
何より、マウスピース自体が回転していないんですよね。跳ねるごとにxz軸方向が変わってほしいし、跳んでいる間もくるくる回転していてほしい。回転させるには四元数と和解しないといけませんが……。

スクリプト

// DAZ Studio version 4.22.0.15 filetype DAZ Script

const v_y_first = 400 // [cm/s]
const v_x = -50 // [cm/s]
const v_z = 20 // [cm/s]
const bounding_time = 30 // [frame]
const restitution = 0.3

var mouthpiece = Scene.findNodeByLabel("MouthGuard")
var pos = mouthpiece.getWSPos(0)
const fps = 10
const fps_v = new DzVec3(fps, fps, fps)
const g = new DzVec3(0, 980, 0) // [cm/s^2]
const canvas_y = 100 // [cm]
var v = new DzVec3(v_x, v_y_first, v_z)

for (var frame = 1; frame < bounding_time; frame++){
	pos = pos.add(v.divide(fps_v))
	if (pos.y <= canvas_y){
		v = new DzVec3(v.x, v.y * -1 * restitution, v.z)
		pos = new DzVec3(pos.x, canvas_y, pos.z)
	}else{
		v = v.subtract(g.divide(fps_v))
	}
	mouthpiece.setWSPos(Scene.getTimeStep().valueOf() * frame, pos)
	print("time: " + (frame / fps) + pos)
}

柱前堂 2024/02/25 21:17

Daz アニメーション

ダウンを喫し、なけなしの体力を振り絞ってなんとかロープ際まで這いずり、やっと掴んだロープを離してしまい目の前で虚しく揺れるロープを眺めることしかできない……の図です。

これは何?

Daz のアニメーション機能を試してみました。

Timeline ペインで時刻を動かしながら1フレームごとに動きをつけ、実行してみてアニメーションの動作確認……した時点でGUIでの反復移動がやってられなくなったので、本番ではスクリプトで動きを指定しました。スクリプト自体は末尾に。

作品としては人物のダメージ描写や表情が未設定とかロープが納まりきってないカメラアングルとか色々残念ですが、実験ということで。
でも、てかてかグローブにロープの影が映っているのはいいですね。

レンダリング時間

気になるレンダリング時間ですが、10fps10秒の100フレームで、100分ほどかかりました。普段Full HD画像一枚を撮るのと同じくらい。
480x270ピクセル、Max samples や Max path Length もかなり落として同等なので、気合入れた画質にしようとすると大変そうです。ライトやピンボケもとくに設定してません。動画は厳しい……。

今後の展望

スクリプトの書き方が分かったので、動かす先の座標さえ分かればちょっとした動きを付けるのは簡単にできそうです。
単純な式で表せる動きなら座標の計算も難しくないはず。ロープの振動のほか、みんな大好きマウスピースの放物線だとか、人物を前後上下させて自然な体の揺れを表現するとか。

夢はでっかくボクシングの動きをさせたいところですが、人体は連動して動くところが多いし単純な軌道でもなさそうなので、気合入れて手動で指定するしかなさそうな気がします……。
関節の連動の仕方をうまく模式化できればスクリプトでもいけるか……?

それはそうと、四元数と和解しなさい。

スクリプト

// DAZ Studio version 4.22.0.15 filetype DAZ Script


// 扱うボーンの取得
var blueRope = Scene.findNode("BoxingRingBody").findNodeChildByLabel("BlueCorner").findNodeChildByLabel("BlueRopeBottomL").findNodeChildByLabel("BlueRope")
var i, target_bone
const target_bone_id = 15
var temp_bone = blueRope.getNodeChild(0)
for (i = 1; i < target_bone_id; i++){
	temp_bone = temp_bone.getNodeChild(0)
}
const target_bone = temp_bone
const reverse_bone = target_bone.getNodeChild(0)
for (temp_bone = reverse_bone; temp_bone.getNumNodeChildren() > 0; temp_bone = temp_bone.getNodeChild(0)){}
const end_bone = temp_bone

// ロープ揺れの各種パラメータ
const secondPerCycle = 2
const reductionFrames = 100
const fps = 10
const amplitude= -50
// 指定フレームごとのロープの位置
function rope_bound(frame){
	const time = Scene.getTimeStep().valueOf() * frame
	// ロープ頂点のy座標。振動しながら徐々に振幅が落ちるように
	const y = amplitude * (reductionFrames - frame) / reductionFrames * Math.cos(2 * Math.PI * frame / fps / secondPerCycle)
	// ロープ始点の曲げ角度。y座標に来るようロープの長さから計算する
	const b_radian = Math.atan(y / (blueRope.getWSPos().x - target_bone.getWSPos().x))
	// 反対側ロープの角度。同様に残りのロープの長さから計算する。
	const e_radian = Math.atan(y / (end_bone.getWSPos().x - reverse_bone.getWSPos().x))
    
    // ロープの各ボーンに動きを設定。四元数のことは何も分からん
    // 第一引数は DzTime 型だが、DzTime のドキュメントには Number 入れていいって書いてある。ていうか DzTime にコンストラクタが用意されてない。
	blueRope.setLocalRot(time, DzQuat(b_radian / Math.PI, 0, 0, 1))
	target_bone.setLocalRot(time, DzQuat(-1 * b_radian / Math.PI, 0, 0, 1))
	reverse_bone.setLocalRot(time, DzQuat(e_radian / Math.PI, 0, 0, 1))
	
}

// 全フレームにそれぞれの時刻での動きを設定
for (i = 0; i <= reductionFrames; i++){
	rope_bound(i)
}

月別アーカイブ

限定特典から探す

記事を検索