Fallout箱庭DIY

「箱庭DIY」Fallout分室

【Fallout4】半透明なStealth Fieldエフェクトの作成実験(Nanako対応編)

スポンサーリンク


AI111
Stable Diffusionさん作の自キャラ再現。
46枚のSSで1時間ほど訓練(RTX3060)しただけですが、思いのほか再現度が高かったのでTOP絵採用w


続き物です。
前回はStealth Field発動時(Stealth Boyみたいなやつ)に、自キャラが半透明になるエフェクトを作りました。ですがNanako環境だと顔がうまく透過しません。
今回はこれのNanako対応作業です。
とはいえ完璧には対応しきれず、若干のビジュアル問題が残ります(透過中のみ)。
前回に比べ、かなり作業量多め。CK、FO4Edit、Material Editor、Nifskope等のツールは使える前提でお願いします。
一応動いてますが、ちょっと汚いコードだと思いますぬ(スクリプト初心者全開)。


※今回も変わらず、試すときは自己責任でお願いします!
ほとんどデバッグ時間取れてないので、何が起こるか判りません!ほぼ4年振りに触ってるってこともありますしwそんな前提でお願いします。

前回の内容はこちら。
f4mod.hatenablog.com

前回までの流れ

前回の軽いおさらい。
こんな感じの透明化エフェクトを作りますが、
アルファ透過率の比較

前回のスクリプトだと、顔が透過せず残ってしまいます。
顔の残った透過状態

こちらが前回のスクリプト。バニラの”PAStealthSoundScript.psc”を改変。


Scriptname PAStealthSoundScriptZIP2 extends activemagiceffect

Sound Property OBJArmorStealthActivate Auto Const Mandatory
Sound Property OBJArmorStealthDeactivate Auto Const Mandatory
float property fAlphaTr = 0.25 Auto ;透過率のproperty宣言(75%透ける)


Event OnEffectStart(Actor akTarget, Actor akCaster) ;ステルス開始
OBJArmorStealthActivate.Play(akCaster) ;ステルス開始時のSE再生
if(Game.GetPlayer() == akTarget)
akTarget.SetAlpha(fAlphaTr, abFade = true) ;透過開始(25%)
EndIf

EndEvent

Event OnEffectFinish(Actor akTarget, Actor akCaster) ;ステルス終了
OBJArmorStealthDeactivate.Play(akCaster) ;ステルス終了時のSE再生
if(Game.GetPlayer() == akTarget)
akTarget.SetAlpha(1.0, abFade = true) ;透過終了
EndIf

EndEvent

これをベースにコードを追加しつつ、あわせて必要なassetを作成していきます。


顔が透過しない原因と対策

表情制御の仕様だと思いますが、Nanakoの顔はDecalになっています。で、僕が試した限りですが、Decalを透過させることが出来ませんでした。alphaは使えますが、閾値基準で表示するかしないかの2択のみぽい(例えば体についた血痕Decalは、透過時に消える)。

マテリアルからDecalを解除すれば、透過可能になるんですが、
顔のDecal解除

顔に支障がでます。
Decal解除の弊害
左は、使わない睫毛(ジト目用)が一部被ってます。目の輪郭線も若干浮かんでるかも。
右のジト目は、上部分に虹彩がはみ出てますね。顔のテクスチャが通常になった影響で、うまく隠せなくなったと思われます(多分…あんまDecal詳しくないので!)。
※目にかぶってる縦線は触角前髪ですw左ほっぺはtattooでござる。紛らわしくてすいません・・・

そこで思い付き。
通常時これだと厳しいですが、透過中なら・・・この程度は許容範囲じゃないですかね?('_')
特に左の方は気づかないと思われます。
という訳で対策方法は、

透過中のみ顔のマテリアルからDecalを解除することにします!

透過時のみ顔のマテリアルを変更

具体的な流れとしては、

  1. ステルス起動
  2. 顔のマテリアルをDecal無しにスワップ
  3. 透過実行
  4. ステルス解除
  5. 透過解除
  6. 顔のマテリアルをDecal(元のやつ)にスワップ

といった処理にします。


5と6を逆にすると、透過中に顔のマテリアルを戻す為、現状の問題点である「顔だけ透過しない」状態になってしまいます。透過解除前の一瞬ですが、見栄えが悪いです。

※重要!※
今回はフォルダ”nana1”のassetに対してのみ変更をします。他の顔や、複数対応する際は各自読み替えをお願いします!

透過時用マテリアルファイルの作成

顔のマテリアルファイル”head.bgsm”を複製して、Decal無し版を作ります。
先程の再掲載。
顔のDecal解除
スクリプトでファイル名を使うので、何かわかりやすい名前を推奨。

プラグインにダミーのMaterial Swapを作成

次はプラグインいきます。
僕は”StealthZipsuit.esp”というプラグイン名で、Zipsuitに透明化ステルス付けました。
※前回も書きましたが、装備MODの説明は省略します。今回はエフェクト作成がメインなので。

スクリプトで操作する為のMaterial Swapを作成。顔のスワップだけなら2個でOKですが、目の対策(後述)でもう4個使う為、計6個になってます。
スクリプト操作用MaterialSwap
設定はスクリプトで行うので、カラッポでいい筈!

Material Swapをスクリプトに記述

前回のスクリプトに追加していきます。
F4SEにMaterial Swapを使える関数があったので、それを使ってみました。
オレンジ色のとこが、追加部分です。

Scriptname PAStealthSoundScriptZIP2 extends activemagiceffect

Sound Property OBJArmorStealthActivate Auto Const Mandatory
Sound Property OBJArmorStealthDeactivate Auto Const Mandatory

float property fAlphaTr = 0.25 Auto ;透過率のproperty宣言(75%透ける)

MatSwap FaceAlpha ;透過用Material Swap(後でPropertyに繋ぐ)
MatSwap FaceOrg ;通常用Material Swap(後でPropertyに繋ぐ)
MatSwap:RemapData[] RemapAry ;マテリアルファイル格納用配列(テンポラリ)
MatSwap:RemapData Remap ;マテリアルファイル格納用変数(テンポラリ)


Event OnInit()

FaceAlpha = Game.GetFormFromFile(0x00232e48, "StealthZipsuit.esp") as MatSwap ;透過用Material Swapのproperty接続
FaceOrg = Game.GetFormFromFile(0x00232e49, "StealthZipsuit.esp") as MatSwap ;通常用Material Swapのproperty接続


RemapAry = new MatSwap:RemapData[0] ;透過用マテリアルファイル取得開始
Remap = new MatSwap:RemapData
Remap.Source = "nanarace\\nana1\\head.bgsm"
Remap.Target= "nanarace\\nana1\\headNoDecal.bgsm"

RemapAry.Add(Remap)
FaceAlpha.SetRemapData(RemapAry) ;取得終了

RemapAry = new MatSwap:RemapData[0] ;通常用マテリアルファイル取得開始
Remap = new MatSwap:RemapData
Remap.Source = "nanarace\\nana1\\head.bgsm"
Remap.Target= "nanarace\\nana1\\head.bgsm"

RemapAry.Add(Remap)
FaceOrg.SetRemapData(RemapAry) ;取得完了

EndEvent


Event OnEffectStart(Actor akTarget, Actor akCaster) ;ステルス開始

OBJArmorStealthActivate.Play(akCaster) ;ステルス開始時のSE再生

if(Game.GetPlayer() == akTarget)

Game.GetPlayer().ApplyMaterialSwap(FaceAlpha) ;透過用マテリアルを適用
akTarget.SetAlpha(fAlphaTr, abFade = true) ;透過開始(25%)

EndIf

EndEvent


Event OnEffectFinish(Actor akTarget, Actor akCaster) ;ステルス終了

OBJArmorStealthDeactivate.Play(akCaster) ;ステルス終了時のSE再生

if(Game.GetPlayer() == akTarget)

akTarget.SetAlpha(1.0, abFade = true) ;透過終了

Game.GetPlayer().ApplyMaterialSwap(FaceOrg) ;通常用マテリアルに戻す

EndIf

EndEvent

ちょっと冗長感が無くもないんですが(僕がスクリプト素人だからそう見えるだけかも?)、Material Swapはこんな感じでないとうまく格納できないようです。CK wikiのを真似てます。
www.creationkit.com
www.creationkit.com

同一プラグイン上でGetFormFromFileを使ったのは、”MatSwap”でのProperty接続がCKでは無理だった為(FO4Editで手書きできたかも?)。

てかapplyだけスクリプトにして、あとはプラグインに書けば良かったのかもしれない('_') 試してないですが・・・

スワップ状態はセーブデータに残らないようなので(ステルス中にセーブしてロードすると顔の透過が消える)、現状と比較するような処理は入れてないです。淡々とスワップ実行してるだけ!

動作確認

一応これで顔も透過するんですが、
顔の透過適用

糸目のにっこり顔(作者のひよこ2号様配布の表情バッチ”smile.txt”に相当)の時がちょっとキツいです。
透過による目のDecal不具合
”ジト目(jitome)”と”にっこり糸目(以下smile)”が重なってます。本来はsmileのDecalでジト目が隠れるんだと思いますが、透過により表示されてしまいました。
これは透過を使う以上、絶対に見えると思うので、ちょっと力業で対策します。

何やらかすかと言いますと、

透過中は”smile”のassetを完全透明化(非表示)にします。

つまり、下に透けてる”jitome”だけにして誤魔化す( ゚Д゚)
弊害として、
 
ステルス中は”smile”の表情が発生しなくなります

まあやむなしです、別に仏頂面になる訳でもないので!


smileのassetを非表示化

残り4つのMaterial Swapを使い、睫毛と目元(どちらかというと眼窩)の2部位を、顔と同じようにスワップします。

マテリアルファイルの独立化

”smile”用メッシュファイルに括られたマテリアルファイルは、他の表情も共用してます。”smile”だけ非表示にするには、これを独立させないとダメですね。

目元”smile_face.nif”と、睫毛”smile_matuge.nif"の2つ。
head.bgsmと ”matuge.bgsm”を複製リネームし、それぞれのメッシュファイルに紐づけ。

head.bgsm”を複製してリネーム
目元用マテリアルファイルを独立化

matuge.bgsm”を複製してリネーム
睫毛用マテリアルファイルを独立化


透過時用のマテリアルファイルを作成

更に複製して、完全透明時のマテリアルファイルを作ります。
Alphaを0にするだけです。

smile_face.nif用と、
目元消し用マテリアルファイル

smile_matuge.nif用。
睫毛消し用マテリアルファイル
これでマテリアルファイル4つ新設完了!

(bugfix)顔白対策

すいません、いきなり何の話だ!?ってなりますよね・・・
実はこの記事書き終わるちょっと前に、1つ大きなバグを見つけまして。
Material Swapすると顔が真っ白になる!という大問題。さながら美白の女王(鈴木そ〇子)
色付きバイザーのせいで、全く気づきませんでしたぬ。
白顔問題
耳からあご先にかけて境界線が見えますね。顔面真っ白。これはステルス解除後も直りません。理由は不明ですが、どうも"Tint”のチェックが無視されてる? slmで肌色いじると直りますし。スワップするとTint Colorとして処理してくれないのかもです。

修正案ですが、スクリプトで直接触れなそうだったので、また強引な修正を('_')。実験記事ということでカンベン!

スクリプトで「口」のHead Partを一旦削除し、すぐに戻します!

Head Partの差し替えが発生すると、Tint Colorが再設定されるようなので(動的に種族変更等できるようにかも?)、これを利用して色を戻します。口にした理由は、差し替え時の点滅が顔だと目立つ為。
1つ解決できなかった問題が。ステルス中は顔白のままになります!
透過中だし気にならんとは思います。顔だけHead Part差し替え、残りをMaterial Swapとやってみたんですが、うまく反映されませんでしたぬ。ここで「口」やると、元に戻ってしまいますし・・・。
なので、もしかするとRusty Face Fix使ってると、うまく動かないかも(Nanako環境には関係ないですが)。


おまけmemo
Material Swap を使わず、Head Partの差し替えだけで対処すれば、もしかしたらうまくいくかもですが・・・
NanakoはHead Partの数がとても多い為、大変な差し替え物量になると思われます(マテリアルファイルはあまり多くない)。透過中の白顔は、個人的には気にならなかった為、ここはスルーすることにしました。
透過用Head Partを使ったRaceに切り替え、なんてA-H-Oな手も考えましたが、切り替え時に立ってしまう為、sneakと相性悪いw
余談ですが、SKSEに比べると、Head Part周りの関数はF4SEは随分少ないようです。

目元と睫毛のMaterial Swapをスクリプトに追加

という訳で以下、現状の最終版です。ちょっと長くなってしまいましたぬ。


Scriptname PAStealthSoundScriptZIP2 extends activemagiceffect

Sound Property OBJArmorStealthActivate Auto Const Mandatory
Sound Property OBJArmorStealthDeactivate Auto Const Mandatory

;Material SwapのProperty宣言
;CKで"MatSwap"のTypeで接続出来なかった為、GetFormFromFileで後で接続。ここでは変数宣言のみ
MatSwap FaceAlpha ;顔(透過)
MatSwap FaceOrg ;顔(通常)
MatSwap SocketAlpha ;smile目元(透過)
MatSwap SocketOrg ;smile目元(通常)
MatSwap LashAlpha ;smile睫毛(透過)
MatSwap LashOrg ;smile睫毛(通常)

MatSwap:RemapData[] RemapAry ;マテリアルファイル格納用テンポラリ
MatSwap:RemapData Remap ;上に同じ

HeadPart Mouth ;透過解除後の顔色修正に使う

float property fAlphaTr = 0.25 Auto ;透過率のproperty宣言


Event OnInit()

;Material SwapのProperty接続
;環境次第でFormIDとプラグイン名が違うので、このままコピペして実験しないように('_')
FaceAlpha = Game.GetFormFromFile(0x00232e48, "StealthZipsuit.esp") as MatSwap
FaceOrg = Game.GetFormFromFile(0x00232e49, "StealthZipsuit.esp") as MatSwap
SocketAlpha = Game.GetFormFromFile(0x00232e4A, "StealthZipsuit.esp") as MatSwap
SocketOrg = Game.GetFormFromFile(0x0023B6EB, "StealthZipsuit.esp") as MatSwap
LashAlpha = Game.GetFormFromFile(0x0023B6EC, "StealthZipsuit.esp") as MatSwap
LashOrg = Game.GetFormFromFile(0x0023B6ED, "StealthZipsuit.esp") as MatSwap

;Nanako本体プラグインから、口のHeadPartを取得
Mouth = Game.GetFormFromFile(0x00001EF7, "AnimeRace_Nanako.esp") as HeadPart


;6個のMaterial Swapにマテリアルファイル(.BGSM)を格納
;sourceはメッシュファイルに記述したマテリアルファイルを指定
;よって戻すときはSourceとTargetが同一になる

;顔(透過)
RemapAry = new MatSwap:RemapData[0]
Remap = new MatSwap:RemapData
Remap.Source = "nanarace\\nana1\\head.bgsm"
Remap.Target= "nanarace\\nana1\\headNoDecal.bgsm"

RemapAry.Add(Remap)
FaceAlpha.SetRemapData(RemapAry)

;顔(通常)
RemapAry = new MatSwap:RemapData[0]
Remap = new MatSwap:RemapData
Remap.Source = "nanarace\\nana1\\head.bgsm"
Remap.Target= "nanarace\\nana1\\head.bgsm"

RemapAry.Add(Remap)
FaceOrg.SetRemapData(RemapAry)

;smile目元(透過)
RemapAry = new MatSwap:RemapData[0]
Remap = new MatSwap:RemapData
Remap.Source = "nanarace\\nana1\\smile_face.bgsm"
Remap.Target= "nanarace\\nana1\\smile_face_alpha.bgsm"

RemapAry.Add(Remap)
SocketAlpha.SetRemapData(RemapAry)

;smile目元(通常)
RemapAry = new MatSwap:RemapData[0]
Remap = new MatSwap:RemapData
Remap.Source = "nanarace\\nana1\\smile_face.bgsm"
Remap.Target= "nanarace\\nana1\\smile_face.bgsm"

RemapAry.Add(Remap)
SocketOrg.SetRemapData(RemapAry)

;smile睫毛(透過)
RemapAry = new MatSwap:RemapData[0]
Remap = new MatSwap:RemapData
Remap.Source = "nanarace\\nana1\\smile_matuge.bgsm"
Remap.Target= "nanarace\\nana1\\smile_matuge_alpha.bgsm"

RemapAry.Add(Remap)
LashAlpha.SetRemapData(RemapAry)

;smile睫毛(通常)
RemapAry = new MatSwap:RemapData[0]
Remap = new MatSwap:RemapData
Remap.Source = "nanarace\\nana1\\smile_matuge.bgsm"
Remap.Target= "nanarace\\nana1\\smile_matuge.bgsm"

RemapAry.Add(Remap)
LashOrg.SetRemapData(RemapAry)

EndEvent

Event OnEffectStart(Actor akTarget, Actor akCaster) ;ステルス開始

OBJArmorStealthActivate.Play(akCaster) ;ステルス開始時のSE再生

if(Game.GetPlayer() == akTarget)

Game.GetPlayer().ApplyMaterialSwap(FaceAlpha) ;透過swap適用(顔)
Game.GetPlayer().ApplyMaterialSwap(SocketAlpha) ;透過swap適用(smile目元)
Game.GetPlayer().ApplyMaterialSwap(LashAlpha) ;透過swap適用(smile睫毛)

akTarget.SetAlpha(fAlphaTr, abFade = true) ;透過開始

EndIf

EndEvent


Event OnEffectFinish(Actor akTarget, Actor akCaster) ;ステルス終了

OBJArmorStealthDeactivate.Play(akCaster) ;ステルス終了時のSE再生

if(Game.GetPlayer() == akTarget)

akTarget.SetAlpha(1.0, abFade = true) ;透過終了


;透過終了後にマテリアルを戻すこと!
;先に顔の透過だけ解除されて不気味になる為( ゚Д゚)
;どのみち一瞬白くなるけど・・・
Game.GetPlayer().ApplyMaterialSwap(FaceOrg) ;通常swap適用(顔)
Game.GetPlayer().ApplyMaterialSwap(SocketOrg) ;通常swap適用(smile目元)
Game.GetPlayer().ApplyMaterialSwap(LashOrg) ;通常swap適用(smile睫毛)


;HeadPartの1つを削除、再追加
;Material Swapでおかしくなった顔色を修正
;headでも勿論直るが、点滅が目立つことがある為、
;目立たない口の中にしてみた!(これでも直ってるので)
Game.GetPlayer().ChangeHeadPart(Mouth, abRemovePart = True)
Game.GetPlayer().ChangeHeadPart(Mouth)

EndIf

EndEvent

Material Swapの所は、顔だけだった所に目元と睫毛を追加しただけで、やってることは一緒。
あとは白顔対策に、Nanako本体のプラグインから口のHead Partを取得して、最後のステルス終了時に一旦削除、すぐ再追加してます。

動作確認

にっこり糸目smileが、jitomeになりました。
これでも微妙に目が睫毛突き抜けてますけど、まあ個人的にはいいかな位w
にっこり糸目をジト目に変更
表情”smile”中は、透過発動で即”jitome”になり、終了と同時に”smile”に戻ります。
眉毛も同じ方法で消せば、ドロシーにならんかも?
どのみち力業が過ぎるので、もっとシンプルに全部の表情維持できればいいんですが('_')

いずれも透過中のみの変更なので、透過してない時の表情は元通り。
stealth解除後は異常無し

なんというか、やってることの割に無駄に長いスクリプトになった感は否定できませぬw
もっとシンプルにやれる方法ないかに・・・。
以上おしまいです!

元に用意してたTOP絵供養でござる。暗闇の海岸にステルス上陸!
深夜の海岸上陸

 

Copyright © 2015 Fallout Hakoniwa DIY All rights reserved .

S.kutsumiya@gmail.com