Skip to content

Commit f5f9664

Browse files
committed
import: Write meshes as binary FBX files.
1 parent c50be3d commit f5f9664

File tree

5 files changed

+44
-17
lines changed

5 files changed

+44
-17
lines changed

VisualPinball.Unity/VisualPinball.Unity.Editor/Import/IVpxPrefab.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,6 @@ internal interface IVpxPrefab
2727

2828
IMainComponent MainComponent { get; }
2929

30-
MeshFilter[] MeshFilters { get; }
31-
3230
bool ExtractMesh { get; }
3331

3432
bool SkipParenting { get; }

VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxPlayfieldPrefab.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ internal class VpxPlayfieldPrefab : IVpxPrefab
2727
{
2828
public GameObject GameObject { get; }
2929
public IMainComponent MainComponent => _playfieldComponent;
30-
public MeshFilter[] MeshFilters => GameObject.GetComponents<MeshFilter>();
3130
public bool ExtractMesh => true;
3231
public bool SkipParenting => true;
3332

VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxPrefab.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ internal class VpxPrefab<TItem, TData, TMainComponent> : IVpxPrefab
3232
{
3333
public GameObject GameObject { get; }
3434
public IMainComponent MainComponent => _mainComponent;
35-
public MeshFilter[] MeshFilters => GameObject.GetComponentsInChildren<MeshFilter>();
3635
public bool ExtractMesh { get; set; }
3736
public bool SkipParenting => false;
3837

VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxSceneConverter.cs

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818
using System.Collections.Generic;
1919
using System.IO;
2020
using System.Linq;
21+
using System.Reflection;
2122
using UnityEditor;
23+
using UnityEditor.Formats.Fbx.Exporter;
2224
using UnityEditor.SceneManagement;
2325
using UnityEngine;
2426
using UnityEngine.SceneManagement;
@@ -244,27 +246,55 @@ private Dictionary<string, IVpxPrefab> InstantiateGameItems()
244246
private Dictionary<string, IMainComponent> UpdateGameItems(Dictionary<string, IVpxPrefab> prefabLookup)
245247
{
246248
var componentLookup = prefabLookup.ToDictionary(x => x.Key, x => x.Value.MainComponent);
247-
foreach (var prefab in prefabLookup.Values) {
248-
prefab.SetReferencedData(_sourceTable, this, this, componentLookup);
249-
prefab.FreeBinaryData();
249+
try {
250+
// pause asset database refreshing
251+
AssetDatabase.StartAssetEditing();
250252

251-
if (prefab.ExtractMesh) {
252-
var mfs = prefab.MeshFilters;
253-
foreach (var mf in mfs) {
254-
var suffix = mfs.Length == 1 ? "" : $" ({mf.gameObject.name})";
255-
var meshFilename = $"{prefab.GameObject.name.ToFilename()}{suffix.ToFilename()}.mesh";
253+
// thanks unity for not letting me pass the options to ModelExporter.ExportObject().
254+
var modelExporter = typeof(ModelExporter);
255+
var optionsProp = modelExporter.GetProperty("DefaultOptions", BindingFlags.Static | BindingFlags.NonPublic);
256+
var optionsValue = optionsProp!.GetValue(null, null);
257+
var optionsType = optionsValue.GetType();
258+
var exportFormatField = optionsType.BaseType!.GetField("exportFormat", BindingFlags.Instance | BindingFlags.NonPublic);
259+
exportFormatField!.SetValue(optionsValue, 1); // set to binary
260+
var exportObject = modelExporter.GetMethod("ExportObjects", BindingFlags.NonPublic | BindingFlags.Static);
261+
262+
// first loop: write fbx files
263+
foreach (var prefab in prefabLookup.Values) {
264+
prefab.SetReferencedData(_sourceTable, this, this, componentLookup);
265+
prefab.FreeBinaryData();
266+
267+
if (prefab.ExtractMesh) {
268+
var meshFilename = $"{prefab.GameObject.name.ToFilename()}.fbx";
256269
var meshPath = Path.Combine(_assetsMeshes, meshFilename);
257270
if (_options.SkipExistingMeshes && File.Exists(meshPath)) {
258-
mf.sharedMesh = AssetDatabase.LoadAssetAtPath<Mesh>(meshPath);
259271
continue;
260272
}
261273
if (File.Exists(meshPath)) {
262274
AssetDatabase.DeleteAsset(meshPath);
263275
}
264-
AssetDatabase.CreateAsset(mf.sharedMesh, meshPath);
276+
277+
// export via reflection, because we need binary.
278+
exportObject!.Invoke(null, new[] { meshPath, new UnityEngine.Object[] {prefab.GameObject}, optionsValue, null });
265279
}
266280
}
267281

282+
} finally {
283+
// resume asset database refreshing
284+
AssetDatabase.StopAssetEditing();
285+
AssetDatabase.Refresh();
286+
}
287+
288+
// second loop: assign them to the game object.
289+
foreach (var prefab in prefabLookup.Values) {
290+
291+
if (prefab.ExtractMesh) {
292+
var meshFilename = $"{prefab.GameObject.name.ToFilename()}.fbx";
293+
var meshPath = Path.Combine(_assetsMeshes, meshFilename);
294+
var mf = prefab.GameObject.GetComponent<MeshFilter>();
295+
mf.sharedMesh = AssetDatabase.LoadAssetAtPath<Mesh>(meshPath);
296+
}
297+
268298
// patch
269299
if (_applyPatch) {
270300
_patcher?.ApplyPatches(prefab.GameObject, _tableGo);
@@ -572,8 +602,8 @@ public GameObject GetGroupParent(string name)
572602
private string GetMeshPath(string parentName, string name)
573603
{
574604
var filename = parentName == name
575-
? $"{parentName.ToFilename()}.mesh"
576-
: $"{parentName.ToFilename()} ({name.ToFilename()}).mesh";
605+
? $"{parentName.ToFilename()}.fbx"
606+
: $"{parentName.ToFilename()} ({name.ToFilename()}).fbx";
577607
return Path.Combine(_assetsMeshes, filename);
578608
}
579609

VisualPinball.Unity/VisualPinball.Unity.Editor/VisualPinball.Unity.Editor.asmdef

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"references": [
55
"Unity.Entities",
66
"Unity.Entities.Hybrid",
7+
"Unity.Formats.Fbx.Editor",
78
"Unity.Mathematics",
89
"Unity.Transforms",
910
"Unity.InputSystem",
@@ -22,4 +23,4 @@
2223
"defineConstraints": [],
2324
"versionDefines": [],
2425
"noEngineReferences": false
25-
}
26+
}

0 commit comments

Comments
 (0)