Blenderで法線転写する際の罠
確認される限り Blender 3.6.0 で発生するデータ転送モディファイアによるBlenderの強制終了もしくはメッシュデータの破壊についての注意喚起です。
Blender 3.5.1 や 3.3.x LTS では発生しません。
2023/07/19 追記:こちらの問題は Blender 3.6.1 で解消されました。
前提の項はBlender初学者にもできるだけわかるようにと書いたもののため、手っ取り早く解決法だけ知れれば良いという方は飛ばしてください。
本稿末尾に本事象が発生するサンプルファイルを添付しています。
概要
データ転送(Data Transfer)モディファイアで法線転写をする際、
転送先のメッシュに大量のシェイプキーが設定されている場合、
Blenderの強制終了やデータ破損の恐れがあります。
強制終了しなかった場合でも見かけ上正常に見えることがあり、
取り返しの付かない破損となる可能性があるため注意が必要です。

左:法線転写が失敗 右:シェイプキーが破損
回避策としては、
「シェイプキーを設定前に法線転写する」
「シェイプキーを一時的に退避し、法線転写後にシェイプキーを転送する」
などの方法があります。
前提
法線転写とは
法線転写とは、あるメッシュの法線を別形状オブジェクトから転写し、
そのメッシュが転写元の形状をしているかのように見せかける方法です。
キャラクターモデリングなどにおいてキャラクターの顔にセルルックな影を落としたい場合などに用いられます。

びっくりした人はたぶん他にもいるはず

左:法線転写あり 右:法線転写なし
わかりやすくするため影を濃く設定している
上記の画像を見ての通り、法線転写をしないと口元がだいぶ悲惨なことになっている事がわかります。
顔の全体の法線から凹凸の要素を消すことでこれを回避し、影を綺麗に表示させることが目的です。
法線とは
メッシュを構成する面の向きです。
UnityやBlenderでモデルを描画する際、ほとんどの場合はこの向きと光源の方向を基に影をどれくらいにするかを決めて描画します。
法線の向きが光源の方向を向いていれば明るくなりますし、そっぽを向いていたら暗くなります。
データ転送(Data Transfer)モディファイア
Blenderにおいて法線転写をする際、使用されるモディファイアです。
転写対象のオブジェクトに追加し、転写元のオブジェクトから各種データをコピーすることができます。


左のCubeを中央のSphireに転写し右のような見た目になる
Blenderではほとんどのモディファイアが「シェイプキーが設定済みの場合、適用不可能」なのですが、このモディファイアの他『変更』という分類に属するモディファイアはシェイプキーが設定されていても適用可能です。
今回は一般的に使用されるであろうデータ転送モディファイアのみを例に上げていますが、恐らく今回注意喚起している問題はこの「シェイプキーが設定されていても適用可能」なモディファイア全てで発生します。

赤枠に囲まれている部分が今回の問題を発生させ得るモディファイア達
何が発生するのか
発生する問題は設定されているシェイプキーの数や設定状況によって異なりますが、大きく分けて2つです。
強制終了
モディファイア適用時にBlenderがエラーなしに強制終了します。
強制終了しない場合でも、継続して何か操作した瞬間に強制終了する場合があります。
自動保存を有効にしていればそこまで戻れますし、適用前にファイルを保存していれば無傷です。
まだ優しさがあります。
データ破損
モディファイア適用時に強制終了しなかった場合にファイルを保存し、開き直すと強制終了を回避できてしまいます。
しかし、モディファイアを適用したオブジェクトのカスタム法線・シェイプキー・頂点グループなどのデータが破損します。(特に並び順最後の方)
強制終了は数分の作業ロストで済みますが、こちらは設定したシェイプキーなどを破壊しまくるため、数時間の作業が水泡に帰す可能性があります。
あまりにもツラい。

左:シェイプキー0の状態 右:シェイプキー適用時

左:法線転写が失敗 右:シェイプキーが破損
回避策
本事象は回避可能です。
新規にモデルを作成しているならば、シェイプキー作成前に法線転写すれば良いだけの話です。
しかしながら、後から調整する場合、既存のモデルに法線転写したい場合は使用できません。
そのため、本項ではオブジェクトを複製してシェイプキーを退避し、法線転写後にシェイプキーを戻す方法を紹介します。
手順
1. オブジェクトを複製し、シェイプキーを退避
(リンク複製ではなく通常の複製である点に注意)

2. 複製元のオブジェクトからシェイプキーをすべて削除


3. 複製元オブジェクトのモディファイアを適用


4. スクリプトですべてのシェイプキーを複製したオブジェクトから復元
スクリプティング(Scripting)タブを開く

※ スクリプティングタブが見当たらない場合、タブ一覧の+ボタンから追加してください

「新規」ボタンをクリックし、真ん中のテキストエリアに以下を貼り付け
import bpy
target_object = bpy.context.view_layer.objects.active
os = bpy.context.selected_objects
os.remove(target_object)
source_object = os[0]
for i in range(1, len(source_object.data.shape_keys.key_blocks)):
source_object.active_shape_key_index = i
bpy.ops.object.shape_key_transfer()

オブジェクト一覧から複製したオブジェクトを選択→Ctrlを押しながら複製元オブジェクトを選択し、画像のような選択状態にする

スクリプトの実行ボタンをクリック
対象オブジェクトの規模やシェイプキーの数によっては実行にめちゃくちゃ時間がかかります。

5. シェイプキーが転送されていることを確認し、完了

サンプルファイル
Sphere_ShapeKey0, 50, 100は、それぞれシェイプキーを0,50,100個設定したオブジェクトです。
それぞれCubeから法線転写するためモディファイアが設定済です。
Sphere_ShapeKey50, 100はモディファイアの適用を行うとBlenderが強制終了するかメッシュのデータが破損します。
本稿は以上です。
お読みいただきありがとうございました。