Last active
May 6, 2022 08:41
-
-
Save esperecyan/28026fc96550bcf822b5401f2e078dba to your computer and use it in GitHub Desktop.
『FBXMeshFileSizeReducer.cs』 Unity 2018.3以降でFBXのメッシュが肥大化する問題を抑制するエディタ拡張。 unitypackage: https://pokemori.booth.pm/items/1961154
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Linq; | |
using System.Collections.Generic; | |
using System.IO; | |
using UnityEngine; | |
using UnityEditor; | |
namespace Esperecyan.Unity.FBXMeshFileSizeReducer | |
{ | |
/// <summary> | |
/// Unity 2018.3以降でFBXのメッシュが肥大化する問題を抑制します。 | |
/// </summary> | |
/// <remarks> | |
/// FBX、およびメッシュがインポートされたときにシェイプキーの法線・接線データを削除 (FBXの場合は「ブレンドシェイプの法線」を「なし」に) します。 | |
/// また、Assetsのメニューから、インポート済みのFBX、メッシュも処理できます。 | |
/// | |
/// VRM正規化後など、処理されたあとにプロジェクトの保存 (Ctrl+S) が必要です。 | |
/// | |
/// 動作確認バージョン: Unity 2018.4.20f1 | |
/// SPDX-License-Identifier: MPL-2.0 | |
/// (Mozilla Public License 2.0) <https://spdx.org/licenses/MPL-2.0.html> | |
/// Author: 100の人 | |
/// 配布元: <https://gist.github.com/esperecyan/28026fc96550bcf822b5401f2e078dba> | |
/// | |
/// 更新履歴: | |
/// 2020-05-19 v2.0.0 | |
/// Unity 2018.4.20f1 において、FBXインポート設定の「ブレンドシェイプの法線」が機能しない不具合が直っていたため、 | |
/// 「Legacy Blend Shape Normals」へチェックを入れる代わりに、同設定を「なし」に | |
/// 2020-04-09 v1.0.0 | |
/// 表記等を修正 | |
/// 2019-07-24 | |
/// FBXインポート時にも処理するように (メッシュ同様に手動で処理する機能を追加) | |
/// 2019-06-03 | |
/// FBXインポート時の代わりに、メッシュが取り出されたとき (インポートされたとき) に処理するように | |
/// すでに取り出されたメッシュを全処理する機能を追加 | |
/// 2019-04-19 | |
/// 公開 | |
/// </remarks> | |
internal class Postprocessor : AssetPostprocessor | |
{ | |
private struct BlendShapeFrame | |
{ | |
internal string shapeName; | |
internal float frameWeight; | |
internal Vector3[] deltaVertices; | |
} | |
[MenuItem("Assets/シェイプキーの法線・接線データを削除", true)] | |
private static bool IsMesh() | |
{ | |
if (!Selection.activeObject) | |
{ | |
return false; | |
} | |
string path = AssetDatabase.GetAssetPath(Selection.activeObject); | |
if (string.IsNullOrEmpty(path)) | |
{ | |
return false; | |
} | |
switch (Path.GetExtension(path).ToLower()) | |
{ | |
case ".fbx": | |
return true; | |
case ".asset": | |
return Selection.activeObject is Mesh && AssetDatabase.LoadAllAssetsAtPath(path).Length == 1; | |
default: | |
return false; | |
} | |
} | |
[MenuItem("Assets/シェイプキーの法線・接線データを削除")] | |
private static void Reduce() | |
{ | |
string path = AssetDatabase.GetAssetPath(Selection.activeObject); | |
string fileName = Path.GetFileName(path); | |
string message = "「" + fileName + "」に法線・接線データをもつシェイプキーはありません。"; | |
if (Path.GetExtension(path).ToLower() == ".fbx") | |
{ | |
if (Postprocessor.tagFBXWithUnusingBlendShapesNormalsAndTangents(path: path)) | |
{ | |
message = "「" + fileName + "」のシェイプキーの法線・接線データが利用されないようマークしました。"; | |
} | |
} | |
else | |
{ | |
if (Postprocessor.deleteBlendShapesNormalsAndTangents(Selection.activeObject as Mesh)) | |
{ | |
message = "「" + fileName + "」のシェイプキーの法線・接線データを削除しました。Ctrl+S などでプロジェクトを保存してください。"; | |
} | |
} | |
EditorUtility.DisplayDialog("FBXMeshFileSizeReducer.cs", message, "OK"); | |
} | |
[MenuItem("Assets/プロジェクト内に存在するすべてのメッシュからシェイプキーの法線・接線データを削除")] | |
private static void ReduceAllMeshes() | |
{ | |
if (!EditorUtility.DisplayDialog( | |
"FBXMeshFileSizeReducer.cs", | |
"プロジェクト内に単独で存在するすべてのメッシュのシェイプキーの、法線・接線データを削除します。" | |
+ "また、FBXについてはシェイプキーの法線・接線データを参照しないように「ブレンドシェイプの法線」を「なし」にします。よろしいですか。", | |
"OK", | |
"キャンセル" | |
)) | |
{ | |
return; | |
} | |
var reducedMeshCount = 0; | |
foreach (string guid in AssetDatabase.FindAssets("t:Mesh")) | |
{ | |
if (Postprocessor.makeBlendShapesNormalsAndTangentsUnuse(path: AssetDatabase.GUIDToAssetPath(guid))) | |
{ | |
reducedMeshCount++; | |
} | |
} | |
EditorUtility.DisplayDialog("FBXMeshFileSizeReducer.cs", reducedMeshCount > 0 | |
? reducedMeshCount + "個のメッシュのシェイプキーの、法線・接線データを削除 (FBXの場合は「ブレンドシェイプの法線」を「なし」に) しました。" | |
+ "Ctrl+S などでプロジェクトを保存してください。\n\n" | |
: "法線・接線データをもつシェイプキーがあるメッシュは、プロジェクト内には存在しません。", "OK"); | |
} | |
private static void OnPostprocessAllAssets( | |
string[] importedAssets, | |
string[] deletedAssets, | |
string[] movedAssets, | |
string[] movedFromAssetPaths | |
) | |
{ | |
foreach (string path in importedAssets) | |
{ | |
Postprocessor.makeBlendShapesNormalsAndTangentsUnuse(path: path); | |
} | |
if (importedAssets.Length == 1 && importedAssets[0].EndsWith("/BlendShape.asset")) | |
{ | |
AssetDatabase.SaveAssets(); | |
} | |
} | |
/// <summary> | |
/// 拡張子に応じて <see cref="Postprocessor.tagFBXWithUnusingBlendShapesNormalsAndTangents"/>、 | |
/// または <see cref="Postprocessor.deleteBlendShapesNormalsAndTangents"/> を実行します。 | |
/// </summary> | |
/// <remarks> | |
/// 対象外の拡張子の場合は何もしません。 | |
/// </remarks> | |
/// <param name="path"></param> | |
/// <returns></returns> | |
private static bool makeBlendShapesNormalsAndTangentsUnuse(string path) | |
{ | |
switch (Path.GetExtension(path).ToLower()) | |
{ | |
case ".fbx": | |
return Postprocessor.tagFBXWithUnusingBlendShapesNormalsAndTangents(path); | |
case ".asset": | |
var assets = AssetDatabase.LoadAllAssetsAtPath(path); | |
if (assets.Length != 1) | |
{ | |
return false; | |
} | |
var mesh = assets[0] as Mesh; | |
if (!mesh) | |
{ | |
return false; | |
} | |
return Postprocessor.deleteBlendShapesNormalsAndTangents(AssetDatabase.LoadAssetAtPath<Mesh>(path)); | |
default: | |
return false; | |
} | |
} | |
/// <summary> | |
/// FBXでシェイプキーの法線・接線データを使用しないようマーク (「ブレンドシェイプの法線」を「なし」に) します。 | |
/// </summary> | |
/// <param name="path"></param> | |
/// <returns>マークを行った場合、すでに行われていた場合は <c>true</c>。</returns> | |
private static bool tagFBXWithUnusingBlendShapesNormalsAndTangents(string path) | |
{ | |
if (AssetDatabase.LoadAllAssetsAtPath(path).All(obj => { | |
var mesh = obj as Mesh; | |
return !mesh || mesh.blendShapeCount == 0; | |
})) | |
{ | |
return false; | |
} | |
var importer = AssetImporter.GetAtPath(path) as ModelImporter; | |
if (importer.importBlendShapeNormals == ModelImporterNormals.None) | |
{ | |
return true; | |
} | |
importer.importBlendShapeNormals = ModelImporterNormals.None; | |
AssetDatabase.ImportAsset(path); | |
return true; | |
} | |
/// <summary> | |
/// シェイプキーの法線・接線データを削除します。 | |
/// </summary> | |
/// <param name="mesh"></param> | |
/// <returns>削除を行った場合 <c>true</c>。</returns> | |
private static bool deleteBlendShapesNormalsAndTangents(Mesh mesh) | |
{ | |
var blendShapeFrames = new List<BlendShapeFrame>(); | |
if (mesh.blendShapeCount == 0) | |
{ | |
return false; | |
} | |
var normalsAndTangentsExisted = false; | |
for (var shapeIndex = 0; shapeIndex < mesh.blendShapeCount; shapeIndex++) | |
{ | |
string shapeName = mesh.GetBlendShapeName(shapeIndex); | |
int frameCount = mesh.GetBlendShapeFrameCount(shapeIndex); | |
for (var frameIndex = 0; frameIndex < frameCount; frameIndex++) | |
{ | |
var deltaVertices = new Vector3[mesh.vertexCount]; | |
var deltaNormals = new Vector3[mesh.vertexCount]; | |
var deltaTangents = new Vector3[mesh.vertexCount]; | |
mesh.GetBlendShapeFrameVertices( | |
shapeIndex, | |
frameIndex, | |
deltaVertices, | |
deltaNormals, | |
deltaTangents | |
); | |
if (!normalsAndTangentsExisted) | |
{ | |
normalsAndTangentsExisted = deltaNormals.Any(normal => normal != Vector3.zero) | |
|| deltaTangents.Any(normal => normal != Vector3.zero); | |
} | |
blendShapeFrames.Add(new BlendShapeFrame | |
{ | |
shapeName = shapeName, | |
frameWeight = mesh.GetBlendShapeFrameWeight(shapeIndex, frameIndex), | |
deltaVertices = deltaVertices, | |
}); | |
} | |
} | |
if (!normalsAndTangentsExisted) | |
{ | |
return false; | |
} | |
mesh.ClearBlendShapes(); | |
foreach (BlendShapeFrame frame in blendShapeFrames) | |
{ | |
mesh.AddBlendShapeFrame(frame.shapeName, frame.frameWeight, frame.deltaVertices, null, null); | |
} | |
EditorUtility.SetDirty(mesh); | |
return true; | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
fileFormatVersion: 2 | |
guid: eaabe383859f4c64fb002aa53ec51565 | |
MonoImporter: | |
externalObjects: {} | |
serializedVersion: 2 | |
defaultReferences: [] | |
executionOrder: 0 | |
icon: {instanceID: 0} | |
userData: | |
assetBundleName: | |
assetBundleVariant: |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment