mirror of
https://github.com/aelurum/AssetStudio.git
synced 2025-05-25 05:40:21 -04:00
- workaround for Unity 5 vertex buffer anomaly
- re-wrote code for loading and extracting bundle files - fixed link problem with instances of skinned geometry - separated normal and bump map texture slots in FBX - added transparency factor in FBX materials
This commit is contained in:
parent
1f2635c877
commit
32855d932e
@ -8,10 +8,9 @@ using Lz4;
|
||||
|
||||
namespace Unity_Studio
|
||||
{
|
||||
public class BundleFile : IDisposable
|
||||
public class BundleFile
|
||||
{
|
||||
private EndianStream Stream;
|
||||
public byte ver1;
|
||||
public int ver1;
|
||||
public string ver2;
|
||||
public string ver3;
|
||||
public List<MemoryAssetsFile> MemoryAssetsFileList = new List<MemoryAssetsFile>();
|
||||
@ -52,84 +51,101 @@ namespace Unity_Studio
|
||||
}
|
||||
}
|
||||
|
||||
Stream = new EndianStream(new MemoryStream(filebuffer), EndianType.BigEndian);
|
||||
using (var b_Stream = new EndianStream(new MemoryStream(filebuffer), EndianType.BigEndian))
|
||||
{
|
||||
readBundle(b_Stream);
|
||||
}
|
||||
}
|
||||
else { Stream = new EndianStream(File.OpenRead(fileName), EndianType.BigEndian); }
|
||||
|
||||
long magicHeader = Stream.ReadInt64();
|
||||
|
||||
if (magicHeader == -361700864190383366 || magicHeader == 6155973689634940258 || magicHeader == 6155973689634611575)
|
||||
else
|
||||
{
|
||||
int dummy = Stream.ReadInt32();
|
||||
ver1 = Stream.ReadByte();
|
||||
ver2 = Stream.ReadStringToNull();
|
||||
ver3 = Stream.ReadStringToNull();
|
||||
using (var b_Stream = new EndianStream(File.OpenRead(fileName), EndianType.BigEndian))
|
||||
{
|
||||
readBundle(b_Stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void readBundle(EndianStream b_Stream)
|
||||
{
|
||||
var header = b_Stream.ReadStringToNull();
|
||||
|
||||
if (header == "UnityWeb" || header == "UnityRaw" || header == "\xFA\xFA\xFA\xFA\xFA\xFA\xFA\xFA")
|
||||
{
|
||||
ver1 = b_Stream.ReadInt32();
|
||||
ver2 = b_Stream.ReadStringToNull();
|
||||
ver3 = b_Stream.ReadStringToNull();
|
||||
if (ver1 < 6) { int bundleSize = b_Stream.ReadInt32(); }
|
||||
else
|
||||
{
|
||||
long bundleSize = b_Stream.ReadInt64();
|
||||
return;
|
||||
}
|
||||
short dummy2 = b_Stream.ReadInt16();
|
||||
int offset = b_Stream.ReadInt16();
|
||||
int dummy3 = b_Stream.ReadInt32();
|
||||
int lzmaChunks = b_Stream.ReadInt32();
|
||||
|
||||
int lzmaSize = 0;
|
||||
int fileSize = Stream.ReadInt32();
|
||||
short dummy2 = Stream.ReadInt16();
|
||||
int offset = Stream.ReadInt16();
|
||||
int dummy3 = Stream.ReadInt32();
|
||||
int lzmaChunks = Stream.ReadInt32();
|
||||
long streamSize = 0;
|
||||
|
||||
for (int i = 0; i < lzmaChunks; i++)
|
||||
{
|
||||
lzmaSize = Stream.ReadInt32();
|
||||
fileSize = Stream.ReadInt32();
|
||||
lzmaSize = b_Stream.ReadInt32();
|
||||
streamSize = b_Stream.ReadInt32();
|
||||
}
|
||||
|
||||
Stream.Position = offset;
|
||||
switch (magicHeader)
|
||||
b_Stream.Position = offset;
|
||||
switch (header)
|
||||
{
|
||||
case -361700864190383366: //.bytes
|
||||
case 6155973689634940258: //UnityWeb
|
||||
case "\xFA\xFA\xFA\xFA\xFA\xFA\xFA\xFA": //.bytes
|
||||
case "UnityWeb":
|
||||
{
|
||||
byte[] lzmaBuffer = new byte[lzmaSize];
|
||||
Stream.Read(lzmaBuffer, 0, lzmaSize);
|
||||
Stream.Close();
|
||||
Stream.Dispose();
|
||||
b_Stream.Read(lzmaBuffer, 0, lzmaSize);
|
||||
|
||||
Stream = new EndianStream(SevenZip.Compression.LZMA.SevenZipHelper.StreamDecompress(new MemoryStream(lzmaBuffer)), EndianType.BigEndian);
|
||||
offset = 0;
|
||||
using (var lzmaStream = new EndianStream(SevenZip.Compression.LZMA.SevenZipHelper.StreamDecompress(new MemoryStream(lzmaBuffer)), EndianType.BigEndian))
|
||||
{
|
||||
getFiles(lzmaStream, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 6155973689634611575: //UnityRaw
|
||||
case "UnityRaw":
|
||||
{
|
||||
|
||||
getFiles(b_Stream, offset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int fileCount = Stream.ReadInt32();
|
||||
for (int i = 0; i < fileCount; i++)
|
||||
{
|
||||
MemoryAssetsFile memFile = new MemoryAssetsFile();
|
||||
memFile.fileName = Stream.ReadStringToNull();
|
||||
int fileOffset = Stream.ReadInt32();
|
||||
fileOffset += offset;
|
||||
fileSize = Stream.ReadInt32();
|
||||
long nextFile = Stream.Position;
|
||||
Stream.Position = fileOffset;
|
||||
|
||||
byte[] buffer = new byte[fileSize];
|
||||
Stream.Read(buffer, 0, fileSize);
|
||||
memFile.memStream = new MemoryStream(buffer);
|
||||
MemoryAssetsFileList.Add(memFile);
|
||||
Stream.Position = nextFile;
|
||||
}
|
||||
}
|
||||
|
||||
Stream.Close();
|
||||
else if (header == "UnityFS")
|
||||
{
|
||||
ver1 = b_Stream.ReadInt32();
|
||||
ver2 = b_Stream.ReadStringToNull();
|
||||
ver3 = b_Stream.ReadStringToNull();
|
||||
long bundleSize = b_Stream.ReadInt64();
|
||||
}
|
||||
}
|
||||
|
||||
~BundleFile()
|
||||
private void getFiles(EndianStream f_Stream, int offset)
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
int fileCount = f_Stream.ReadInt32();
|
||||
for (int i = 0; i < fileCount; i++)
|
||||
{
|
||||
MemoryAssetsFile memFile = new MemoryAssetsFile();
|
||||
memFile.fileName = f_Stream.ReadStringToNull();
|
||||
int fileOffset = f_Stream.ReadInt32();
|
||||
fileOffset += offset;
|
||||
int fileSize = f_Stream.ReadInt32();
|
||||
long nextFile = f_Stream.Position;
|
||||
f_Stream.Position = fileOffset;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Stream.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
byte[] buffer = new byte[fileSize];
|
||||
f_Stream.Read(buffer, 0, fileSize);
|
||||
memFile.memStream = new MemoryStream(buffer);
|
||||
MemoryAssetsFileList.Add(memFile);
|
||||
f_Stream.Position = nextFile;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -583,6 +583,8 @@ namespace Unity_Studio
|
||||
|
||||
BitArray m_CurrentChannels = new BitArray(new int[1] { a_Stream.ReadInt32() });
|
||||
m_VertexCount = a_Stream.ReadInt32();
|
||||
//int singleStreamStride = 0;//used tor unity 5
|
||||
int streamCount = 0;
|
||||
|
||||
#region streams for 3.5.0 - 3.5.7
|
||||
if (version[0] < 4)
|
||||
@ -608,9 +610,6 @@ namespace Unity_Studio
|
||||
#region channels and streams for 4.0.0 and later
|
||||
else
|
||||
{
|
||||
//int singleStreamStride = 0;//used tor unity 5
|
||||
int streamCount = 0;
|
||||
|
||||
m_Channels = new ChannelInfo[a_Stream.ReadInt32()];
|
||||
for (int c = 0; c < m_Channels.Length; c++)
|
||||
{
|
||||
@ -639,28 +638,49 @@ namespace Unity_Studio
|
||||
m_Streams[s].frequency = a_Stream.ReadUInt16();
|
||||
}
|
||||
}
|
||||
else //create streams
|
||||
{
|
||||
m_Streams = new StreamInfo[streamCount];
|
||||
for (int s = 0; s < streamCount; s++)
|
||||
{
|
||||
m_Streams[s] = new StreamInfo();
|
||||
m_Streams[s].channelMask = new BitArray(new int[1] { 0 });
|
||||
m_Streams[s].offset = 0;
|
||||
if (s > 0) { m_Streams[s].offset = m_Streams[s - 1].offset + m_Streams[s - 1].stride * m_VertexCount; }
|
||||
m_Streams[s].stride = 0;
|
||||
foreach (var m_Channel in m_Channels)
|
||||
{
|
||||
if (m_Channel.stream == s) { m_Streams[s].stride += m_Channel.dimension * (4 / (int)Math.Pow(2, m_Channel.format)); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
//actual Vertex Buffer
|
||||
byte[] m_DataSize = new byte[a_Stream.ReadInt32()];
|
||||
a_Stream.Read(m_DataSize, 0, m_DataSize.Length);
|
||||
|
||||
if (version[0] >= 5) //create streams
|
||||
{
|
||||
m_Streams = new StreamInfo[streamCount];
|
||||
for (int s = 0; s < streamCount; s++)
|
||||
{
|
||||
m_Streams[s] = new StreamInfo();
|
||||
m_Streams[s].channelMask = new BitArray(new int[1] { 0 });
|
||||
m_Streams[s].offset = 0;
|
||||
m_Streams[s].stride = 0;
|
||||
|
||||
foreach (var m_Channel in m_Channels)
|
||||
{
|
||||
if (m_Channel.stream == s) { m_Streams[s].stride += m_Channel.dimension * (4 / (int)Math.Pow(2, m_Channel.format)); }
|
||||
}
|
||||
|
||||
if (s > 0)
|
||||
{
|
||||
m_Streams[s].offset = m_Streams[s - 1].offset + m_Streams[s - 1].stride * m_VertexCount;
|
||||
//sometimes there are 8 bytes between streams
|
||||
//this is NOT an alignment, even if sometimes it may seem so
|
||||
|
||||
if (streamCount == 2) { m_Streams[s].offset = m_DataSize.Length - m_Streams[s].stride * m_VertexCount; }
|
||||
else
|
||||
{
|
||||
m_VertexCount = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/*var absoluteOffset = a_Stream.Position + 4 + m_Streams[s].offset;
|
||||
if ((absoluteOffset % m_Streams[s].stride) != 0)
|
||||
{
|
||||
m_Streams[s].offset += m_Streams[s].stride - (int)(absoluteOffset % m_Streams[s].stride);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region compute FvF
|
||||
|
@ -18,6 +18,7 @@ using System.Web.Script.Serialization;
|
||||
Load parent nodes even if they are not selected to provide transformations?
|
||||
For extracting bundles, first check if file exists then decompress
|
||||
Double-check channelgroup argument in new FMOD Studio API system.playSound method
|
||||
Font index error in Dreamfall Chapters
|
||||
*/
|
||||
|
||||
namespace Unity_Studio
|
||||
@ -33,7 +34,8 @@ namespace Unity_Studio
|
||||
//private AssetsFile mainDataFile = null;
|
||||
private string mainPath = "";
|
||||
private string productName = "";
|
||||
|
||||
private string[] fileTypes = new string[7] { "maindata.", "level*.", "*.assets", "*.sharedAssets", "CustomAssetBundle-*", "CAB-*", "BuildPlayer-*" };
|
||||
|
||||
Dictionary<string, Dictionary<string, string>> jsonMats;
|
||||
Dictionary<string, SortedDictionary<int, ClassStrStruct>> AllClassStructures = new Dictionary<string, SortedDictionary<int, ClassStrStruct>>();
|
||||
|
||||
@ -133,7 +135,6 @@ namespace Unity_Studio
|
||||
//TODO find a way to read data directly instead of merging files
|
||||
MergeSplitAssets(mainPath);
|
||||
|
||||
string[] fileTypes = new string[7] { "maindata.", "level*.", "*.assets", "*.sharedAssets", "CustomAssetBundle-*", "CAB-*", "BuildPlayer-*" };
|
||||
for (int t = 0; t < fileTypes.Length; t++)
|
||||
{
|
||||
string[] fileNames = Directory.GetFiles(mainPath, fileTypes[t], SearchOption.AllDirectories);
|
||||
@ -284,56 +285,60 @@ namespace Unity_Studio
|
||||
{
|
||||
StatusStripUpdate("Decompressing " + Path.GetFileName(bundleFileName) + "...");
|
||||
|
||||
using (BundleFile b_File = new BundleFile(bundleFileName))
|
||||
BundleFile b_File = new BundleFile(bundleFileName);
|
||||
|
||||
List<AssetsFile> b_assetsfileList = new List<AssetsFile>();
|
||||
|
||||
foreach (var memFile in b_File.MemoryAssetsFileList) //filter unity files
|
||||
{
|
||||
List<AssetsFile> b_assetsfileList = new List<AssetsFile>();
|
||||
|
||||
foreach (var memFile in b_File.MemoryAssetsFileList) //filter unity files
|
||||
bool validAssetsFile = false;
|
||||
switch (Path.GetExtension(memFile.fileName))
|
||||
{
|
||||
bool validAssetsFile = false;
|
||||
switch (Path.GetExtension(memFile.fileName))
|
||||
{
|
||||
case ".assets":
|
||||
case ".sharedAssets":
|
||||
validAssetsFile = true;
|
||||
break;
|
||||
case "":
|
||||
if (memFile.fileName == "mainData" || Regex.IsMatch(memFile.fileName, "level.*?") || Regex.IsMatch(memFile.fileName, "CustomAssetBundle-.*?") || Regex.IsMatch(memFile.fileName, "CAB-.*?") || Regex.IsMatch(memFile.fileName, "BuildPlayer-.*?")) { validAssetsFile = true; }
|
||||
break;
|
||||
}
|
||||
|
||||
if (validAssetsFile)
|
||||
{
|
||||
StatusStripUpdate("Loading " + memFile.fileName);
|
||||
memFile.fileName = Path.GetDirectoryName(bundleFileName) + "\\" + memFile.fileName; //add path for extract location
|
||||
|
||||
AssetsFile assetsFile = new AssetsFile(memFile.fileName, new EndianStream(memFile.memStream, EndianType.BigEndian));
|
||||
if (assetsFile.fileGen == 6 && Path.GetFileName(bundleFileName) != "mainData") //2.6.x and earlier don't have a string version before the preload table
|
||||
{
|
||||
//make use of the bundle file version
|
||||
assetsFile.m_Version = b_File.ver3;
|
||||
assetsFile.version = Array.ConvertAll((b_File.ver3.Split(new string[] { ".", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "\n" }, StringSplitOptions.RemoveEmptyEntries)), int.Parse);
|
||||
assetsFile.buildType = b_File.ver3.Split(new string[] { ".", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
b_assetsfileList.Add(assetsFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
memFile.memStream.Close();
|
||||
}
|
||||
case ".assets":
|
||||
case ".sharedAssets":
|
||||
validAssetsFile = true;
|
||||
break;
|
||||
case "":
|
||||
validAssetsFile = (memFile.fileName == "mainData" ||
|
||||
Regex.IsMatch(memFile.fileName, "level.*?") ||
|
||||
Regex.IsMatch(memFile.fileName, "CustomAssetBundle-.*?") ||
|
||||
Regex.IsMatch(memFile.fileName, "CAB-.*?") ||
|
||||
Regex.IsMatch(memFile.fileName, "BuildPlayer-.*?"));
|
||||
break;
|
||||
}
|
||||
|
||||
assetsfileList.AddRange(b_assetsfileList);//will the streams still be available for reading data?
|
||||
|
||||
foreach (var assetsFile in b_assetsfileList)
|
||||
if (validAssetsFile)
|
||||
{
|
||||
foreach (var sharedFile in assetsFile.sharedAssetsList)
|
||||
StatusStripUpdate("Loading " + memFile.fileName);
|
||||
//create dummy path to be used for asset extraction
|
||||
memFile.fileName = Path.GetDirectoryName(bundleFileName) + "\\" + memFile.fileName;
|
||||
|
||||
AssetsFile assetsFile = new AssetsFile(memFile.fileName, new EndianStream(memFile.memStream, EndianType.BigEndian));
|
||||
if (assetsFile.fileGen == 6 && Path.GetFileName(bundleFileName) != "mainData") //2.6.x and earlier don't have a string version before the preload table
|
||||
{
|
||||
sharedFile.fileName = Path.GetDirectoryName(bundleFileName) + "\\" + sharedFile.fileName;
|
||||
var loadedSharedFile = b_assetsfileList.Find(aFile => aFile.filePath == sharedFile.fileName);
|
||||
if (loadedSharedFile != null) { sharedFile.Index = assetsfileList.IndexOf(loadedSharedFile); }
|
||||
//make use of the bundle file version
|
||||
assetsFile.m_Version = b_File.ver3;
|
||||
assetsFile.version = Array.ConvertAll((b_File.ver3.Split(new string[] { ".", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "\n" }, StringSplitOptions.RemoveEmptyEntries)), int.Parse);
|
||||
assetsFile.buildType = b_File.ver3.Split(new string[] { ".", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
b_assetsfileList.Add(assetsFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
memFile.memStream.Close();
|
||||
}
|
||||
}
|
||||
|
||||
assetsfileList.AddRange(b_assetsfileList);//will the streams still be available for reading data?
|
||||
|
||||
foreach (var assetsFile in b_assetsfileList)
|
||||
{
|
||||
foreach (var sharedFile in assetsFile.sharedAssetsList)
|
||||
{
|
||||
sharedFile.fileName = Path.GetDirectoryName(bundleFileName) + "\\" + sharedFile.fileName;
|
||||
var loadedSharedFile = b_assetsfileList.Find(aFile => aFile.filePath == sharedFile.fileName);
|
||||
if (loadedSharedFile != null) { sharedFile.Index = assetsfileList.IndexOf(loadedSharedFile); }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -395,29 +400,29 @@ namespace Unity_Studio
|
||||
string extractPath = bundleFileName + "_unpacked\\";
|
||||
Directory.CreateDirectory(extractPath);
|
||||
|
||||
using (BundleFile b_File = new BundleFile(bundleFileName))
|
||||
BundleFile b_File = new BundleFile(bundleFileName);
|
||||
|
||||
foreach (var memFile in b_File.MemoryAssetsFileList)
|
||||
{
|
||||
foreach (var memFile in b_File.MemoryAssetsFileList)
|
||||
string filePath = extractPath + memFile.fileName.Replace('/', '\\');
|
||||
if (!Directory.Exists(Path.GetDirectoryName(filePath)))
|
||||
{
|
||||
string filePath = extractPath + memFile.fileName.Replace('/','\\');
|
||||
if (!Directory.Exists(Path.GetDirectoryName(filePath)))
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(filePath));
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(filePath));
|
||||
|
||||
}
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
StatusStripUpdate("File " + memFile.fileName + " already exists");
|
||||
}
|
||||
else
|
||||
{
|
||||
StatusStripUpdate("Extracting " + Path.GetFileName(memFile.fileName));
|
||||
extractedCount += 1;
|
||||
}
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
StatusStripUpdate("File " + memFile.fileName + " already exists");
|
||||
}
|
||||
else
|
||||
{
|
||||
StatusStripUpdate("Extracting " + Path.GetFileName(memFile.fileName));
|
||||
extractedCount += 1;
|
||||
|
||||
using (FileStream file = new FileStream(filePath, FileMode.Create, System.IO.FileAccess.Write))
|
||||
{
|
||||
memFile.memStream.WriteTo(file);
|
||||
}
|
||||
using (FileStream file = new FileStream(filePath, FileMode.Create, System.IO.FileAccess.Write))
|
||||
{
|
||||
memFile.memStream.WriteTo(file);
|
||||
memFile.memStream.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1039,6 +1044,7 @@ namespace Unity_Studio
|
||||
{
|
||||
if (firstSortColumn != e.Column)
|
||||
{
|
||||
//sorting column has been changed
|
||||
reverseSort = false;
|
||||
secondSortColumn = firstSortColumn;
|
||||
}
|
||||
@ -1074,6 +1080,7 @@ namespace Unity_Studio
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
assetListView.EndUpdate();
|
||||
|
||||
resizeAssetListColumns();
|
||||
@ -1859,6 +1866,11 @@ namespace Unity_Studio
|
||||
mb.AppendFormat("\n\t\t\tP: \"ShininessExponent\", \"Number\", \"\", \"A\",{0}", m_Float.second);
|
||||
mb.AppendFormat("\n\t\t\tP: \"Shininess\", \"Number\", \"\", \"A\",{0}", m_Float.second);
|
||||
break;
|
||||
case "_Transparency":
|
||||
mb.Append("\n\t\t\tP: \"TransparentColor\", \"Color\", \"\", \"A\",1,1,1");
|
||||
mb.AppendFormat("\n\t\t\tP: \"TransparencyFactor\", \"Number\", \"\", \"A\",{0}", m_Float.second);
|
||||
mb.AppendFormat("\n\t\t\tP: \"Opacity\", \"Number\", \"\", \"A\",{0}", (1 - m_Float.second));
|
||||
break;
|
||||
default:
|
||||
mb.AppendFormat("\n;\t\t\tP: \"{0}\", \"Number\", \"\", \"A\",{1}", m_Float.first, m_Float.second);
|
||||
break;
|
||||
@ -1914,10 +1926,12 @@ namespace Unity_Studio
|
||||
cb2.Append("SpecularColor\"");
|
||||
break;
|
||||
case "_NormalMap":
|
||||
case "_BumpMap":
|
||||
case "gNormalSampler":
|
||||
cb2.Append("NormalMap\"");
|
||||
break;
|
||||
case "_BumpMap":
|
||||
cb2.Append("Bump\"");
|
||||
break;
|
||||
default:
|
||||
cb2.AppendFormat("{0}\"", m_TexEnv.name);
|
||||
break;
|
||||
@ -2143,6 +2157,10 @@ namespace Unity_Studio
|
||||
AssetPreloadData MeshPD;
|
||||
if (assetsfileList.TryGetGameObject(m_SkinnedMeshRenderer.m_GameObject, out m_GameObject) && assetsfileList.TryGetPD(m_SkinnedMeshRenderer.m_Mesh, out MeshPD))
|
||||
{
|
||||
//generate unique Geometry ID for instanced mesh objects
|
||||
//I should find a way to preserve instances at least when exportDeformers is not selected
|
||||
var keepID = MeshPD.uniqueID;
|
||||
MeshPD.uniqueID = SkinnedMeshPD.uniqueID;
|
||||
Mesh m_Mesh = new Mesh(MeshPD);
|
||||
MeshFBX(m_Mesh, MeshPD.uniqueID, ob);
|
||||
|
||||
@ -2282,6 +2300,8 @@ namespace Unity_Studio
|
||||
bool stop = true;
|
||||
}
|
||||
}
|
||||
|
||||
MeshPD.uniqueID = keepID;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user