AIイラストの衣装を脱がしたい。…脱がしたくない?
AIイラストのおかげで、「あっちのエロゲに、こっちのシステムがあれば…」と長年悶々としていたストレスがすごい勢いで解消される充実した日々を過ごせております。
こうやって実装すれば簡単だよー、という技術情報をどんどん開示したくとも、ぼくでは絵が用意できないので、実例が出せませんでしたが、AIイラストがあればそりゃもうジャンジャンバリバリ実例が出せる。最高過ぎる。
さて、そんなぼくにとって救世主にも等しいStableDiffusion様ですが、唯一残念なのは、CG差分が非常に作りづらいこと。
表情差分くらいなら範囲が狭いので、Inpaintツールで何とかなるけど、同じキャラで衣装だけ変更したいとか、同じ衣装のままポーズだけ変更したいとか、かなり難しい。いや、はっきり言うと今のぼくには不可能。
絶対にこの子をヒロインにする!!というほどの熱い情熱があれば、首切り取った絵に別人の体を移植する、という字面だけ見ると猟奇的なアレコレをしつつ、LoRA学習させれば何とかなるかも知れないけれど、学習は時間がかかるので今はやりたくない。
もっと先にやりたいことがあるのです。
何がやりたいのか。
服を、脱がせたい。
…………………はい、エロ漫画風イラストでは脱がせてました。
でも違うンです。
1枚目からババーンと乳が出るとかさあ!
コマが変わったらぽろーん、とかじゃなくてさあ!
徐々に、脱がしたくない?
過程も大事だと思うンだよ。ぼくは。
そこで、Promptで「skirt lift」や「shirt lift」(たくし上げ)の強度を上げつつ、脱ぎ掛けのパターンをいくつか作れないかと半日粘ってみたんだけど……………………やっぱダメだったんッスよ…。
秒間30コマの動きが見たいとまでは言わないからさあ!!
せめて、服に手をかける→半脱ぎ→全脱ぎの3パターン程度で妥協するからさあ!!
なんとか、服を脱ぐ過程を………見させてくれよ………頼むよ………(漢泣き
チート能力を手に入れたぼくは異世界で夢想する
あなたの指に不思議なチカラが宿ったようです。
またろくでもない予感がするわ
その指をどうするつもりなの?
どうしてこんなことばかり
思いつくの~
でゅふwww
………いやすまない。これがやりたかったわけじゃないんだ。
これはこれで好きだけども…。
今のぼくにはこのくらいのチカラしかないんだ…許してほしい…。
軽く技術解説
今回は今までのようなお手軽お気楽なCSSアニメーションとはちょっと違います。
スタイルシートでも、-webkit-mask-imageプロパティを使えば、複数枚のマスク画像を重ねてギリギリできないこともなさそうでしたが、最終的にはJavaScript頼りになりそうなので、じゃあ最初からJavaScriptとcanvasでええやん、ってことで今回はガチのスクリプトです。
canvasタグを2枚重ねして、下に裸の絵、上に服装だけ置いてます。そして、マウスがクリックされた位置にマスク画像を載せるだけ。言うのは簡単だけれど、canvasの操作は出来ることが多いだけにコード量も多くなるので、ちと面倒くさいです。難しいわけじゃなく面倒くさいだけなので、やる気のあるJavaScript初心者はぜひ挑戦してみてほしい。
全部解説すると長くなりすぎるから、一番大事なマスクの部分と、一番面倒なレスポンシブ対応についてだけ書いておこうかな?
canvas_cloth.onclick = function () {
ctx_cloth.globalCompositeOperation = 'destination-out';
let rect = this.getBoundingClientRect();
let size = img_cloth.width / 100;
let mask_x = ((event.clientX - rect.left) / canvas.clientWidth * img_cloth.width);
let mask_y = ((event.clientY - rect.top) / canvas.clientHeight * img_cloth.height);
let mask_add = (img_cloth.width / 100);
let mask_count = 0;
let timeId = setInterval(function () {
mask_count++;
mask_x -= (size/2);
mask_y -= (size/2);
ctx_cloth.drawImage(img_mask, mask_x, mask_y, size*mask_count, size*mask_count);
if (mask_count >= 20) {
clearInterval(timeId);
}
}, 20);
}
canvas取得からのコンテキスト作成は基本中の基本過ぎるのでさすがに端折ります。
作成したコンテキストの globalCompositeOperationプロパティに destination-out を設定するのがキモ。このプロパティを設定したキャンバス上に、黒塗りしたスプラッシュ図形を重ねると黒い部分だけが透過されます。つまり、服の絵の上に黒い墨をブシャーしたら服が消えるわけだ。
上のコードでいうところの img_mask のsrcにはsvg画像(透過情報さえ付いてればpng画像でも構わない)がセットされていて、その画像は下記のとおり。
Inkscapeの解説動画※見ながらササっと作った図形なので、必要であればフリー素材としてお好きにお使いください。
前に作ったおしっこや精液と同じく、そのうちご自由にどうぞ素材を集めた記事作ります。
そして一番面倒くさいのがマウス座標の算出。絶対PCでしか見ないORスマホでしか見ないと決まっているなら簡単なのだけれど、両方に対応するためにはあらゆるcanvasのサイズに対応しなきゃならない。
元画像は1024x1024pxなのだけれど、実際に画面上に表示された際には縦x横が何ピクセルなのかは、その端末によって異なる。なので、そのとき(=クリックされた瞬間)にcanvasの横幅を取得。そこを最大値としたときに、マウスカーソルが何%の位置にいるのか算出する必要があります。それがこの部分。
let rect = this.getBoundingClientRect();
mask_x = ((event.clientX - rect.left) / canvas.clientWidth * img_cloth.width);
thisはcanvasなので、getBoundingClientRectで現在のcanvasの絶対座標を取得。マウスの絶対座標との差分で相対座標を取得。
そして、その差分が現在表示されているcanvasの最大幅に比べて何%くらいなのか、を計算しているわけです。
マスクを置くべき座標がわかったら、今度はアニメーション。CSSアニメーションのようにキーフレーム指定してハイおしまい、とはいかないため、setInterval関数を使い、自前でアニメーション動作を作ります。
マスクのサイズは200x200pxなので、20ミリ秒ごとに10pxずつ、20回拡大すればジュワっと広がってみえるかな、と。
単に拡大するだけだと、マウス位置から右下に向かって大きくなってしまい、違和感バリバリなので、マスクを描画する座標も2分の1ずつズラしてあげます。
……………だめっすね。文章で書くと余計ややこしいや!後はソースを読んで理解しろください。
ベース絵
最初、着衣した全身絵を重ねてたんだけど、それだと服が減ったときに表情変えられないなと気が付いて、体を消し消しして服だけの画像も使いました。
Prompt
1girl,loli,kawaii,small breasts,standing
,blonde two side up hair with ribon,red eyes
,(white off shoulder blouse,white panty,pleated skirt:0)
,(naked,nude:1.2),(surprised face,open mouth:1.4),(blush:1.4)
,looking at viewer
,thigh up
,in simple background
,NSFW
,best quality
Negative prompt: (worst quality, low quality, monochrome:1.2), bad anatomy, lowres, watermark, signature, text, username, bad hands, extra hands, extra arms, bad fingers, missing fingers, extra fingers, multipul angle, split view, photorealistic, 3D, high contrast, badhandv4
Steps: 20, Sampler: Euler a, CFG scale: 7, Seed: 3918642074, Size: 512x512, Model hash: fdffd3c312, Model: ambientmix-half, Denoising strength: 0.5, Clip skip: 2, Hires upscale: 2, Hires upscaler: Latent
ヌードと服の差分作るときは、まずヌードから先に作ることを推奨。
最初、着衣状態のキャラを生成してから、ヌード差分を作ろうとしたら全然うまく出来ませんでした。
上のPromptで「(white off shoulder blouse,white panty,pleated skirt:0)」とわざわざ0指定しているのは、img2imgで差分作るときに、ここの数値を1にするだけで、服を着せられるからです。
まとめ
無駄に凝ったスプラッシュ画像(黒インク)にしたんだけど、あんまインクの形に消えているように見えなくて残念だった。しょんぼり。
でも、このインクも白くすれば精液画像として使えそうで、オラわくわくしてきたぞ。














