はじめに
スキンはボディ(胴体、手、足)とフェイス(顔)に分かれています。
手段は主に3通りあります。
- SKSEのSetSkin/SetFaceTextureSet関数
- RaceMenuのAddSkinOverride系関数
- RaceMenuのAddNodeOverride系関数
SKSEの関数はプラグインでのWorn ArmorやTextureSetの指定をまるごと差し替えます。部分的に変更できないのと動作コストが高いのがデメリットです。
RaceMenuのAddSkinOverride系関数は部分的に変更できます。例えばGlossinessのみを変更することが可能です。コストも安く済みます。フェイスに対応していないらしく、そこがデメリットになります。RaceMenuを開くと失われるようです。
RaceMenuのAddNodeOverride系関数はフェイスにも対応しています。RaceMenuにおけるOverlayのことです。使い方にクセがあります。CTDのリスクがあるのもデメリットです。
ボディ
SKSEのSetSkin関数
ボディのスキンを切り替えます。スキンとはArmorのことです。
SetSkin関数の引数のArmorは、設定したいArmorを指定します。ActorのスキンのデフォルトはActorBaseで指定しているWorn Armorになりますが、これを上書きする形になるようです。
ActorBaseでWorn Armorが設定されていない場合は、RaceのSkinの指定が適用された状態になっていますが、Actorのスキンを設定することで上書きされます。
サンプルコードです。
Function UpdateSkin()
Armor kNewSkin = none
Int iNeckDelta = 0.5
; (kNewSkinを設定する)
; スキンを設定する
Game.GetPlayer().GetActorBase().SetSkin(kNewSkin)
; 表示を更新する
Game.GetPlayer().QueueNiNodeUpdate()
; 首の隙間を補正する
Game.GetPlayer().UpdateWeight(iNeckDelta)
EndFunction
SetSkin関数を実行するとNeckDeltaがリセットされるようです。ActorのWeightを変更していて首の隙間を補正している場合、首の隙間が復活します。再度補正する必要があります。Actorが抜刀していると、抜刀アニメーションが発生します。
おそらく内部的にアニメーション処理が初期化されるのでしょう。そこで、抜刀しているのであれば、納刀まで補正を遅らせます。
Function UpdateSkin()
; (略)
if Game.GetPlayer().IsWeaponDrawn()
RegisterForAnimationEvent(Game.GetPlayer(), "weaponSheathe")
else
UnregisterForAnimationEvent(Game.GetPlayer(), "weaponSheathe")
Game.GetPlayer().UpdateWeight(NeckDelta)
endif
EndFunction
Event OnAnimationEvent(ObjectReference akSource, string asEventName)
UnregisterForAnimationEvent(Game.GetPlayer(), "weaponSheathe")
Game.GetPlayer().UpdateWeight(NeckDelta)
EndEvent
この関数はコストが高いらしく、Actorが初期化される関係でカクツキが発生するため、あまりオススメできません。
元に戻すには、元のArmorが必要になります。
RaceMenuのAddSkinOverride系関数
テクスチャの設定を切り替えます。
サンプルコードです。
Function UpdateSkin()
TextureSet kNewBody = none
TextureSet kNewHand = none
; (TextureSetを設定する)
NiOverride.AddSkinOverrideTextureSet(Game.GetPlayer(), true, false, 0x04, 6, -1, kNewBody, true) ; Body
NiOverride.AddSkinOverrideTextureSet(Game.GetPlayer(), true, false, 0x80, 6, -1, kNewBody, true) ; Feet
NiOverride.AddSkinOverrideTextureSet(Game.GetPlayer(), true, false, 0x08, 6, -1, kNewHand, true) ; Hands
EndFunction
第4引数でArmorのスロットを指定します。
第5引数でKeyを指定します。Keyの一覧はnioverride.pscに記述されています。6はShaderTextureSetになります。
Keyの型によって関数を使い分けます。
Keyの型 | 関数 |
---|---|
float | AddSkinOverrideFloat |
int | AddSkinOverrideInt |
bool | AddSkinOverrideBool |
string | AddSkinOverrideString |
TextureSet | AddSkinOverrideTextureSet |
第8引数のpersistにfalseを設定すると変更が一時的なものになり、Weightの変更やSkinの設定など初期化が行われるタイミングで元に戻ります。使い勝手が悪くなるのでtrueにするほうがいいでしょう。
こちらはActorが初期化されないらしく、カクツキがありません。
RaceMenuのAddNodeOverride系関数
解説は準備中です。
フェイス
SKSEのSetFaceTextureSet
フェイスのテクスチャを切り替えます。テクスチャとはTextureSetのことです。
サンプルコードです。
Function UpdateSkin()
TextureSet kNewHead = none
; (TextureSetを設定する)
Game.GetPlayer().GetActorBase().SetFaceTextureSet(kNewHead)
EndFunction
元に戻すには、元のTextureSetが必要になります。
RaceMenuのAddSkinOverride系関数
AddSkinOverride系関数はフェイスには使えないようです。
第4引数でHEADのスロットを指定しても変化が見られないようです。
RaceMenuのAddNodeOverride系関数
第4引数でKeyを指定します。Keyの型によって関数を使い分けます。
Keyの型 | 関数 |
---|---|
float | AddNodeOverrideFloat |
int | AddNodeOverrideInt |
bool | AddNodeOverrideBool |
string | AddNodeOverrideString |
TextureSet | AddNodeOverrideTextureSet |
第3引数のNodeでメッシュのNodeらしきものを指定します。
ActorBaseで指定されているフェイスのNodeを取得するサンプルです。
String Function GetHeadNodeName(Actor akTarget)
ActorBase kActorBase = akTarget.GetActorBase()
Int i = kActorBase.GetNumHeadParts()
while i > 0
i -= 1
String sNodeName = kActorBase.GetNthHeadPart(i).GetPartName()
if StringUtil.Find(sNodeName, "Head") >= 0
if NiOverride.GetNodePropertyString(akTarget, false, sNodeName, 9, 7)
return sNodeName
endif
endif
endwhile
return ""
EndFunction
SKSEのStringUtil.Findで強引にそれらしいNodeを特定しています。
RaceMenuのOverlayのNodeを指定する場合は、以下になります。
部位 | Node | Overlayの数 |
---|---|---|
顔 | Face[ovl0] | NiOverride.GetNumFaceOverlays() |
胴 | Body[ovl0] | NiOverride.GetNumBodyOverlays() |
手 | Hands[ovl0] | NiOverride.GetNumHandOverlays() |
足 | Feet[ovl0] | NiOverride.GetNumFeetOverlays() |
0の部分がOverlayの番号で、[ovl0]、[ovl1]、[ovl2]という感じで指定します。
Overlayの数は、顔ならGetNumFaceOverlaysで取得します。
NodeにActorBaseで指定されているNodeを指定する場合
見た目には問題はないようです。
致命的な不具合として、ShaderTintColorを変更している最中にRaceMenuを表示しようとするとCTDします。
CTDしない状態に戻すにはRemoveNodeOverrideを実行した後にWeightを変更するなどしてActorに反映させる必要がります。この反映時に稀にCTDします。
NodeにOverlayを指定する場合
ShaderTextureの指定が必須のようです。指定しないと変化が見られません。
SpellのEffectShaderが表示されない問題があります。