Add option to manually bind UV map types

This commit is contained in:
VaDiM
2025-03-27 18:11:00 +03:00
parent e8ca265a43
commit e1e43439c3
17 changed files with 381 additions and 349 deletions

View File

@ -1,5 +1,7 @@
using AssetStudio.FbxInterop;
using System.IO;
using System.Text.Json;
using System.Collections.Generic;
#if NETFRAMEWORK
using AssetStudio.PInvoke;
@ -30,9 +32,7 @@ namespace AssetStudio
public static class Exporter
{
public static void Export(string path, IImported imported, bool eulerFilter, float filterPrecision,
bool allNodes, bool skins, bool animation, bool blendShape, bool castToBone, float boneSize, bool exportAllUvsAsDiffuseMaps, float scaleFactor, int versionIndex, bool isAscii)
public static void Export(string path, IImported imported, Settings fbxSettings)
{
var file = new FileInfo(path);
var dir = file.Directory;
@ -47,16 +47,88 @@ namespace AssetStudio
var name = Path.GetFileName(path);
using (var exporter = new FbxExporter(name, imported, allNodes, skins, castToBone, boneSize, exportAllUvsAsDiffuseMaps, scaleFactor, versionIndex, isAscii))
using (var exporter = new FbxExporter(name, imported, fbxSettings))
{
exporter.Initialize();
exporter.ExportAll(blendShape, animation, eulerFilter, filterPrecision);
exporter.ExportAll();
}
Directory.SetCurrentDirectory(currentDir);
}
}
public sealed class Settings
{
public bool EulerFilter { get; set; }
public float FilterPrecision { get; set; }
public bool ExportAllNodes { get; set; }
public bool ExportSkins { get; set; }
public bool ExportAnimations { get; set; }
public bool ExportBlendShape { get; set; }
public bool CastToBone { get; set; }
public float BoneSize { get; set; }
public bool ExportAllUvsAsDiffuseMaps { get; set; }
public float ScaleFactor { get; set; }
public int FbxVersionIndex { get; set; }
public int FbxFormat { get; set; }
public Dictionary<int,int> UvBindings { get; set; }
public bool IsAscii => FbxFormat == 1;
public Settings()
{
Init();
}
public Settings(bool eulerFilter, float filterPrecision, bool exportAllNodes, bool exportSkins, bool exportAnimations, bool exportBlendShape, bool castToBone, float boneSize,
bool exportAllUvsAsDiffuseMaps, float scaleFactor, int fbxVersionIndex, int fbxFormat, Dictionary<int, int> uvBindings)
{
EulerFilter = eulerFilter;
FilterPrecision = filterPrecision;
ExportAllNodes = exportAllNodes;
ExportSkins = exportSkins;
ExportAnimations = exportAnimations;
ExportBlendShape = exportBlendShape;
CastToBone = castToBone;
BoneSize = (int)boneSize;
ExportAllUvsAsDiffuseMaps = exportAllUvsAsDiffuseMaps;
ScaleFactor = scaleFactor;
FbxVersionIndex = fbxVersionIndex;
FbxFormat = fbxFormat;
UvBindings = uvBindings;
}
public void Init()
{
var uvDict = new Dictionary<int, int>();
for (var i = 0; i < 8; i++)
{
uvDict[i] = i + 1;
}
EulerFilter = true;
FilterPrecision = 0.25f;
ExportAllNodes = true;
ExportSkins = true;
ExportAnimations = true;
ExportBlendShape = true;
CastToBone = false;
ExportAllUvsAsDiffuseMaps = false;
BoneSize = 10;
ScaleFactor = 1.0f;
FbxFormat = 0;
FbxVersionIndex = 3;
UvBindings = uvDict;
}
public static Settings FromBase64(string base64String)
{
var settingsData = System.Convert.FromBase64String(base64String);
return JsonSerializer.Deserialize<Settings>(settingsData);
}
public string ToBase64()
{
return System.Convert.ToBase64String(JsonSerializer.SerializeToUtf8Bytes(this));
}
}
}
}

View File

@ -11,29 +11,15 @@ namespace AssetStudio.FbxInterop
private readonly string _fileName;
private readonly IImported _imported;
private readonly bool _allNodes;
private readonly bool _exportSkins;
private readonly bool _castToBone;
private readonly float _boneSize;
private readonly bool _exportAllUvsAsDiffuseMaps;
private readonly float _scaleFactor;
private readonly int _versionIndex;
private readonly bool _isAscii;
private readonly Fbx.Settings _settings;
internal FbxExporter(string fileName, IImported imported, bool allNodes, bool exportSkins, bool castToBone, float boneSize, bool exportAllUvsAsDiffuseMaps, float scaleFactor, int versionIndex, bool isAscii)
internal FbxExporter(string fileName, IImported imported, Fbx.Settings fbxSettings)
{
_context = new FbxExporterContext();
_fileName = fileName;
_imported = imported;
_allNodes = allNodes;
_exportSkins = exportSkins;
_castToBone = castToBone;
_boneSize = boneSize;
_exportAllUvsAsDiffuseMaps = exportAllUvsAsDiffuseMaps;
_scaleFactor = scaleFactor;
_versionIndex = versionIndex;
_isAscii = isAscii;
_settings = fbxSettings;
}
~FbxExporter()
@ -64,13 +50,13 @@ namespace AssetStudio.FbxInterop
IsDisposed = true;
}
internal void Initialize()
private void Initialize()
{
var is60Fps = _imported.AnimationList.Count > 0 && _imported.AnimationList[0].SampleRate.Equals(60.0f);
_context.Initialize(_fileName, _scaleFactor, _versionIndex, _isAscii, is60Fps);
_context.Initialize(_fileName, _settings, is60Fps);
if (!_allNodes)
if (!_settings.ExportAllNodes)
{
var framePaths = SearchHierarchy();
@ -78,8 +64,10 @@ namespace AssetStudio.FbxInterop
}
}
internal void ExportAll(bool blendShape, bool animation, bool eulerFilter, float filterPrecision)
internal void ExportAll()
{
Initialize();
var meshFrames = new List<ImportedFrame>();
ExportRootFrame(meshFrames);
@ -97,16 +85,14 @@ namespace AssetStudio.FbxInterop
SetJointsNode(_imported.RootFrame, null, true);
}
if (blendShape)
if (_settings.ExportBlendShape)
{
ExportMorphs();
}
if (animation)
if (_settings.ExportAnimations)
{
ExportAnimations(eulerFilter, filterPrecision);
ExportAnimations(_settings.EulerFilter, _settings.FilterPrecision);
}
ExportScene();
@ -134,7 +120,7 @@ namespace AssetStudio.FbxInterop
private void SetJointsFromImportedMeshes()
{
if (!_exportSkins)
if (!_settings.ExportSkins)
{
return;
}
@ -156,12 +142,12 @@ namespace AssetStudio.FbxInterop
}
}
SetJointsNode(_imported.RootFrame, bonePaths, _castToBone);
SetJointsNode(_imported.RootFrame, bonePaths, _settings.CastToBone);
}
private void SetJointsNode(ImportedFrame rootFrame, HashSet<string> bonePaths, bool castToBone)
{
_context.SetJointsNode(rootFrame, bonePaths, castToBone, _boneSize);
_context.SetJointsNode(rootFrame, bonePaths, castToBone, _settings.BoneSize);
}
private void PrepareMaterials()
@ -173,7 +159,7 @@ namespace AssetStudio.FbxInterop
{
foreach (var meshFrame in meshFrames)
{
_context.ExportMeshFromFrame(rootFrame, meshFrame, _imported.MeshList, _imported.MaterialList, _imported.TextureList, _exportSkins, _exportAllUvsAsDiffuseMaps);
_context.ExportMeshFromFrame(rootFrame, meshFrame, _imported.MeshList, _imported.MaterialList, _imported.TextureList, _settings);
}
}

View File

@ -142,10 +142,7 @@ namespace AssetStudio.FbxInterop
private static extern void AsFbxMeshCreateElementNormal(IntPtr mesh);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxMeshCreateDiffuseUV(IntPtr mesh, int uv);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxMeshCreateNormalMapUV(IntPtr mesh, int uv);
private static extern void AsFbxMeshCreateUVMap(IntPtr mesh, int uvIndex, int uvType);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxMeshCreateElementTangent(IntPtr mesh);

View File

@ -59,11 +59,11 @@ namespace AssetStudio.FbxInterop
}
}
internal void Initialize(string fileName, float scaleFactor, int versionIndex, bool isAscii, bool is60Fps)
internal void Initialize(string fileName, Fbx.Settings fbxSettings, bool is60Fps)
{
EnsureNotDisposed();
var b = AsFbxInitializeContext(_pContext, fileName, scaleFactor, versionIndex, isAscii, is60Fps, out var errorMessage);
var b = AsFbxInitializeContext(_pContext, fileName, fbxSettings.ScaleFactor, fbxSettings.FbxVersionIndex, fbxSettings.IsAscii, is60Fps, out var errorMessage);
if (!b)
{
@ -173,12 +173,12 @@ namespace AssetStudio.FbxInterop
AsFbxPrepareMaterials(_pContext, materialCount, textureCount);
}
internal void ExportMeshFromFrame(ImportedFrame rootFrame, ImportedFrame meshFrame, List<ImportedMesh> meshList, List<ImportedMaterial> materialList, List<ImportedTexture> textureList, bool exportSkins, bool exportAllUvsAsDiffuseMaps)
internal void ExportMeshFromFrame(ImportedFrame rootFrame, ImportedFrame meshFrame, List<ImportedMesh> meshList, List<ImportedMaterial> materialList, List<ImportedTexture> textureList, Fbx.Settings fbxSettings)
{
var meshNode = _frameToNode[meshFrame];
var mesh = ImportedHelpers.FindMesh(meshFrame.Path, meshList);
ExportMesh(rootFrame, materialList, textureList, meshNode, mesh, exportSkins, exportAllUvsAsDiffuseMaps);
ExportMesh(rootFrame, materialList, textureList, meshNode, mesh, fbxSettings);
}
private IntPtr ExportTexture(ImportedTexture texture)
@ -207,12 +207,12 @@ namespace AssetStudio.FbxInterop
return pTex;
}
private void ExportMesh(ImportedFrame rootFrame, List<ImportedMaterial> materialList, List<ImportedTexture> textureList, IntPtr frameNode, ImportedMesh importedMesh, bool exportSkins, bool exportAllUvsAsDiffuseMaps)
private void ExportMesh(ImportedFrame rootFrame, List<ImportedMaterial> materialList, List<ImportedTexture> textureList, IntPtr frameNode, ImportedMesh importedMesh, Fbx.Settings fbxSettings)
{
var boneList = importedMesh.BoneList;
var totalBoneCount = 0;
var hasBones = false;
if (exportSkins && boneList?.Count > 0)
if (fbxSettings.ExportSkins && boneList?.Count > 0)
{
totalBoneCount = boneList.Count;
hasBones = true;
@ -253,17 +253,18 @@ namespace AssetStudio.FbxInterop
AsFbxMeshCreateElementNormal(mesh);
}
for (int i = 0; i < importedMesh.hasUV.Length; i++)
for (var i = 0; i < importedMesh.hasUV.Length; i++)
{
if (!importedMesh.hasUV[i]) { continue; }
if (!importedMesh.hasUV[i])
continue;
if (i == 1 && !exportAllUvsAsDiffuseMaps)
if (fbxSettings.ExportAllUvsAsDiffuseMaps)
{
AsFbxMeshCreateNormalMapUV(mesh, 1);
AsFbxMeshCreateUVMap(mesh, i, 0);
}
else
else if(fbxSettings.UvBindings[i] > 0) //if checked
{
AsFbxMeshCreateDiffuseUV(mesh, i);
AsFbxMeshCreateUVMap(mesh, i, fbxSettings.UvBindings[i]);
}
}