Last active
January 31, 2025 18:31
-
-
Save TitanX101/304d131534ecc134bccca5467372c5cb to your computer and use it in GitHub Desktop.
GFBMDL for Unity. This script, converted from https://github.com/RandomTBush/RTB-3DSMax-Scripts/blob/main/Scripts/PokemonSwitch_GFBMDL-TRMDL.ms, was created for personal use to facilitate the importation of PLGPE-SWSH models as FBX into Unity. Please note that the TRMDL part is not included. I am sharing it in the hope that it may be useful to o…
This file contains 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
// Original maxscript autor: RandomTalkingBush | |
// https://github.com/RandomTBush/RTB-3DSMax-Scripts/blob/main/Scripts/PokemonSwitch_GFBMDL-TRMDL.ms | |
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Linq; | |
using UnityEngine; | |
using Autodesk.Fbx; | |
namespace Empress { | |
public static class GFBMDL { | |
public enum FbxFormat { | |
ASCII, | |
Binary | |
} | |
public enum VertexColor { | |
Color1, | |
Color2 | |
} | |
// =============================================================================================================== | |
// Export settigns | |
// =============================================================================================================== | |
const FbxFormat FBX_FORMTAT = FbxFormat.ASCII; | |
const VertexColor VERTEX_COLOR = VertexColor.Color1; | |
// =============================================================================================================== | |
static float ReadHalfFloat(BinaryReader fstream) { | |
var N = fstream.ReadUInt16(); | |
int S = (N >> 15) & 0x01; | |
int Ef = (N >> 10) & 0x1F; | |
int M = N & 0x3FF; | |
if (Ef == 0 && M == 0) | |
return (float)(Math.Pow(-1.0, S) * 0.0); | |
if (Ef == 0 && M != 0) | |
return (float)(Math.Pow(-1.0, S) * Math.Pow(2.0, -14) * (M / Math.Pow(2.0, 10))); | |
if (Ef > 0 && Ef < 31) | |
return (float)(Math.Pow(-1.0, S) * Math.Pow(2.0, Ef - 15) * (1 + M / Math.Pow(2.0, 10))); | |
if (Ef == 31 && M == 0) | |
return (float)(Math.Pow(-1.0, S) * double.PositiveInfinity); | |
if (Ef == 31 && M != 0) | |
return 0; //hack// should be #inf | |
return 0; | |
} | |
struct Bone_Info_Struct { | |
public int Bone1, Bone2, Bone3, Bone4; | |
} | |
struct Weight_Info_Struct { | |
public float Weight1, Weight2, Weight3, Weight4; | |
} | |
struct weight_data { | |
public List<int> boneids; | |
public List<float> weights; | |
} | |
struct MatData_Struct { | |
public string MatName; | |
public string MatCol0; | |
public float MatUVScaleU; | |
public float MatUVScaleV; | |
public float MatUVTrsU; | |
public float MatUVTrsV; | |
public float MatUVRot; | |
public float MatUVScale2U; | |
public float MatUVScale2V; | |
public float MatUVTrs2U; | |
public float MatUVTrs2V; | |
public float MatUVRot2; | |
public override readonly string ToString() { | |
return $"Name: {MatName} | " + | |
$"Col0: {MatCol0} | " + | |
$"UVScaleU: {MatUVScaleU} | " + | |
$"UVScaleV: {MatUVScaleV} | " + | |
$"UVTrsU: {MatUVTrsU} | " + | |
$"UVTrsV: {MatUVTrsV} | " + | |
$"UVRot: {MatUVRot} | " + | |
$"UVScale2U: {MatUVScale2U} | " + | |
$"UVScale2V: {MatUVScale2V} | " + | |
$"UVTrs2U: {MatUVTrs2U} | " + | |
$"UVTrs2V: {MatUVTrs2V} | " + | |
$"UVRot2: {MatUVRot2}"; | |
} | |
} | |
static FbxNode GetNodeByName(this IEnumerable<FbxNode> bones, string nodeName) { | |
foreach (var node in bones) { | |
if (node.GetName() == nodeName) | |
return node; | |
} | |
return null; | |
} | |
/*[MenuItem("Tools/Import GFBMDL Test")] | |
static void Test() { | |
Import("F:\\Pokemon\\Decrypt\\Pokemon Sword\\Exported\\Zacian.gfbmdl"); | |
}*/ | |
/// <summary> | |
/// | |
/// </summary> | |
/// <param name="fname"></param> | |
/// <exception cref="Exception"></exception> | |
public static void Import(string fname) { | |
/*fname = getOpenFileName \ | |
caption: "Nintendo Switch Pokémon Model File" \ | |
types: "Nintendo Switch Pokémon LGPE / SwSh Model File (*.gfbmdl)|*.gfbmdl" \ | |
historyCategory: "GFBMDLPresets"*/ | |
if (!File.Exists(fname)) | |
return; | |
using var f = new BinaryReader(File.OpenRead(fname)); | |
var fDir = Path.GetDirectoryName(fname); | |
var g = Path.GetFileName(fname); | |
var st = Time.time; | |
var VertColors = VERTEX_COLOR; | |
var BoneArray = new Dictionary<int, FbxNode>(); | |
var BoneRigArray = new List<string>(); | |
var BoneName_array = new List<string>(); | |
var VisGroupBone_array = new List<string>(); | |
var MatStringArray = new List<string>(); | |
var TexStringArray = new List<string>(); | |
var MatData_array = new List<MatData_Struct>(); | |
// Fbx scene | |
using var fbxManager = FbxManager.Create(); | |
var fbxScene = FbxScene.Create(fbxManager, Path.GetFileNameWithoutExtension(g)); | |
var rootNode = fbxScene.GetRootNode(); | |
FbxPose bindPose = null; | |
f.BaseStream.Seek(0x04, SeekOrigin.Begin); | |
ushort SwShCheck = f.ReadUInt16(); | |
if (SwShCheck == 0x00) | |
f.BaseStream.Seek(0x28, SeekOrigin.Begin); | |
else | |
f.BaseStream.Seek(0x2C, SeekOrigin.Begin); | |
var TexNameDataOffset = f.BaseStream.Position + f.ReadInt32(); | |
var MatNameDataOffset = f.BaseStream.Position + f.ReadInt32(); | |
var Unk2DataOffset = f.BaseStream.Position + f.ReadInt32(); | |
var Unk1DataOffset = f.BaseStream.Position + f.ReadInt32(); | |
var ShaderDataOffset = f.BaseStream.Position + f.ReadInt32(); | |
var VisGroupDataOffset = f.BaseStream.Position + f.ReadInt32(); | |
var VertDataOffset = f.BaseStream.Position + f.ReadInt32(); | |
var BoneDataOffset = f.BaseStream.Position + f.ReadInt32(); | |
Debug.Log("Unknown1 (materials) offset: " + Unk1DataOffset); | |
Debug.Log("Unknown2 (blank?) offset: " + Unk2DataOffset); | |
f.BaseStream.Seek(MatNameDataOffset, SeekOrigin.Begin); | |
int MatNameCount = f.ReadInt32(); | |
for (int m = 0; m < MatNameCount; m++) { | |
long MatNameOffset = f.BaseStream.Position + f.ReadInt32(); | |
long MatRet = f.BaseStream.Position; | |
f.BaseStream.Seek(MatNameOffset, SeekOrigin.Begin); | |
int MatNameLength = f.ReadInt32(); | |
var MatName = new string(f.ReadChars(MatNameLength)); | |
MatStringArray.Add(MatName); | |
f.BaseStream.Seek(MatRet, SeekOrigin.Begin); | |
} | |
Debug.Log("--------------------"); | |
Debug.Log("Material names:"); | |
foreach (string matName in MatStringArray) | |
Debug.Log(matName); | |
Debug.Log("--------------------"); | |
f.BaseStream.Seek(TexNameDataOffset, SeekOrigin.Begin); | |
int TexNameCount = f.ReadInt32(); | |
for (int t = 0; t < TexNameCount; t++) { | |
long TexNameOffset = f.BaseStream.Position + f.ReadInt32(); | |
long TexRet = f.BaseStream.Position; | |
f.BaseStream.Seek(TexNameOffset, SeekOrigin.Begin); | |
int TexNameLength = f.ReadInt32(); | |
var TexName = new string(f.ReadChars(TexNameLength)); | |
TexStringArray.Add(TexName); | |
f.BaseStream.Seek(TexRet, SeekOrigin.Begin); | |
} | |
Debug.Log("Texture names:"); | |
foreach (string texName in TexStringArray) | |
Debug.Log(texName); | |
Debug.Log("--------------------"); | |
f.BaseStream.Seek(BoneDataOffset, SeekOrigin.Begin); | |
var BoneCount = f.ReadInt32(); | |
for (int b = 0; b < BoneCount; b++) { | |
long BoneOffset = f.BaseStream.Position + f.ReadInt32(); | |
long BoneRet = f.BaseStream.Position; | |
f.BaseStream.Seek(BoneOffset, SeekOrigin.Begin); | |
Debug.Log("Bone " + b + " start: " + BoneOffset); | |
long BoneInfoOffset = f.BaseStream.Position - f.ReadInt32(); | |
f.BaseStream.Seek(BoneInfoOffset, SeekOrigin.Begin); | |
ushort BoneInfoLength = f.ReadUInt16(); | |
ushort BoneStringStart = f.ReadUInt16(); | |
ushort BoneUnk2Start = f.ReadUInt16(); | |
ushort BoneUnk1Start = f.ReadUInt16(); | |
ushort BoneParentStart = f.ReadUInt16(); | |
ushort BoneBlank3Start = f.ReadUInt16(); | |
ushort BoneByteStart = f.ReadUInt16(); | |
ushort BoneSclStart = f.ReadUInt16(); | |
ushort BoneRotStart = f.ReadUInt16(); | |
ushort BoneTrsStart = f.ReadUInt16(); | |
ushort BoneRigFlag2 = f.ReadUInt16(); // 16 = "rigged", 20 = "unrigged" | |
ushort BoneRigFlag1 = f.ReadUInt16(); // 4 = "rigged", 8 = "unrigged" | |
f.BaseStream.Seek(BoneOffset + BoneTrsStart, SeekOrigin.Begin); | |
float BoneTX = f.ReadSingle(); | |
float BoneTY = f.ReadSingle(); | |
float BoneTZ = f.ReadSingle(); | |
f.BaseStream.Seek(BoneOffset + BoneRotStart, SeekOrigin.Begin); | |
float BoneRX = f.ReadSingle(); | |
float BoneRY = f.ReadSingle(); | |
float BoneRZ = f.ReadSingle(); | |
f.BaseStream.Seek(BoneOffset + BoneSclStart, SeekOrigin.Begin); | |
float BoneSX = f.ReadSingle(); | |
float BoneSY = f.ReadSingle(); | |
float BoneSZ = f.ReadSingle(); | |
int BoneParent = 0; | |
if (BoneParentStart != 0x00) { | |
f.BaseStream.Seek(BoneOffset + BoneParentStart, SeekOrigin.Begin); | |
BoneParent = f.ReadInt32(); | |
} | |
f.BaseStream.Seek(BoneOffset + BoneStringStart, SeekOrigin.Begin); | |
int BoneStrLen = f.ReadInt32(); | |
var BoneName = new string(f.ReadChars(BoneStrLen)); | |
if (BoneRigFlag1 == 4) | |
BoneRigArray.Add(BoneName); | |
BoneName_array.Add(BoneName); | |
// Bones | |
var tfm = new FbxAMatrix(); | |
tfm.SetS(new FbxVector4(BoneSX, BoneSY, BoneSZ)); | |
tfm.SetR(new FbxVector4(BoneRX * Mathf.Rad2Deg, BoneRY * Mathf.Rad2Deg, BoneRZ * Mathf.Rad2Deg)); | |
tfm.SetT(new FbxVector4(BoneTX, BoneTY, BoneTZ)); | |
// Crear un nuevo nodo para representar el hueso | |
var newBone = FbxNode.Create(fbxManager, BoneName); | |
newBone.LclScaling.Set(new FbxDouble3(tfm.GetS().X, tfm.GetS().Y, tfm.GetS().Z)); | |
newBone.LclRotation.Set(new FbxDouble3(tfm.GetR().X, tfm.GetR().Y, tfm.GetR().Z)); | |
newBone.LclTranslation.Set(new FbxDouble3(tfm.GetT().X, tfm.GetT().Y, tfm.GetT().Z)); | |
// Establecer el atributo del nodo | |
var joint = FbxSkeleton.Create(fbxManager, BoneName); | |
joint.SetSkeletonType(FbxSkeleton.EType.eLimbNode); | |
newBone.SetNodeAttribute(joint); | |
// Si el hueso tiene un padre, establecerlo | |
if (BoneArray.TryGetValue(BoneParent, out FbxNode pBone)) | |
pBone.AddChild(newBone); | |
BoneArray[b] = newBone; | |
f.BaseStream.Seek(BoneRet, SeekOrigin.Begin); | |
} | |
// Assign bones to root node | |
rootNode.AddChild(BoneArray[0]); | |
f.BaseStream.Seek(VisGroupDataOffset, SeekOrigin.Begin); | |
var VisGroupCount = f.ReadInt32(); | |
for (int v = 0; v < VisGroupCount; v++) { | |
long VisGroupOffset = f.BaseStream.Position + f.ReadInt32(); | |
long VisGroupRet = f.BaseStream.Position; | |
f.BaseStream.Seek(VisGroupOffset, SeekOrigin.Begin); | |
Debug.Log("VisGroup " + v.ToString() + " start: " + f.BaseStream.Position.ToString()); | |
long VisPtr = f.BaseStream.Position - f.ReadInt32(); | |
f.BaseStream.Seek(VisPtr, SeekOrigin.Begin); | |
ushort VisGroupHeadLen = f.ReadUInt16(); | |
ushort VisGroupUnk1Ptr, VisGroupVisBonePtr, VisGroupUnk2Ptr, VisGroupBoundPtr, VisGroupUnk3Ptr = 0; | |
switch (VisGroupHeadLen) { | |
default: | |
throw new Exception("Unknown header length!"); | |
case 0x000A: | |
VisGroupUnk1Ptr = f.ReadUInt16(); | |
VisGroupVisBonePtr = f.ReadUInt16(); | |
VisGroupUnk2Ptr = f.ReadUInt16(); | |
VisGroupBoundPtr = f.ReadUInt16(); | |
break; | |
case 0x000C: | |
VisGroupUnk1Ptr = f.ReadUInt16(); | |
VisGroupVisBonePtr = f.ReadUInt16(); | |
VisGroupUnk2Ptr = f.ReadUInt16(); | |
VisGroupBoundPtr = f.ReadUInt16(); | |
VisGroupUnk3Ptr = f.ReadUInt16(); | |
break; | |
} | |
f.BaseStream.Seek(VisGroupOffset + VisGroupBoundPtr, SeekOrigin.Begin); | |
float VisBoundMinX = f.ReadSingle(); | |
float VisBoundMinY = f.ReadSingle(); | |
float VisBoundMinZ = f.ReadSingle(); | |
float VisBoundMaxX = f.ReadSingle(); | |
float VisBoundMaxY = f.ReadSingle(); | |
float VisBoundMaxZ = f.ReadSingle(); | |
f.BaseStream.Seek(VisGroupOffset + VisGroupVisBonePtr, SeekOrigin.Begin); | |
int VisBoneName = f.ReadInt32(); | |
VisGroupBone_array.Add(BoneName_array[VisBoneName]); | |
Debug.Log("VisGroup " + v.ToString() + " end: " + f.BaseStream.Position.ToString()); | |
f.BaseStream.Seek(VisGroupRet, SeekOrigin.Begin); | |
} | |
// Shader Data | |
f.BaseStream.Seek(ShaderDataOffset, SeekOrigin.Begin); | |
var MatShadCount = f.ReadInt32(); | |
for (int x = 0; x < MatShadCount; x++) { | |
string MatCol0 = "null"; | |
float MatUVScaleU = 1.0f, MatUVScaleV = 1.0f, MatUVTrsU = 0, MatUVTrsV = 0, MatUVRot = 0; | |
float MatUVScale2U = 1.0f, MatUVScale2V = 1.0f, MatUVTrs2U = 0, MatUVTrs2V = 0, MatUVRot2 = 0; | |
long MatShadOffset = f.BaseStream.Position + f.ReadInt32(); | |
long MatRet = f.BaseStream.Position; | |
f.BaseStream.Seek(MatShadOffset, SeekOrigin.Begin); | |
long MatShadPropOff = f.BaseStream.Position - f.ReadInt32(); | |
f.BaseStream.Seek(MatShadPropOff, SeekOrigin.Begin); | |
ushort MatShadPropHeadLen = f.ReadUInt16(); | |
ushort MatShadPropProp = f.ReadUInt16(); | |
ushort MatShadPropMatString = f.ReadUInt16(); | |
ushort MatShadPropShadString = f.ReadUInt16(); | |
ushort MatShadPropUnk1 = f.ReadUInt16(); | |
ushort MatShadPropUnk2 = f.ReadUInt16(); | |
ushort MatShadPropUnk3 = f.ReadUInt16(); | |
ushort MatShadPropParam1 = f.ReadUInt16(); | |
ushort MatShadPropParam2 = f.ReadUInt16(); | |
ushort MatShadPropParam3 = f.ReadUInt16(); | |
ushort MatShadPropParam4 = f.ReadUInt16(); | |
ushort MatShadPropParam5 = f.ReadUInt16(); | |
ushort MatShadPropParam6 = f.ReadUInt16(); | |
ushort MatShadPropTexList = f.ReadUInt16(); | |
ushort MatShadPropParamA = f.ReadUInt16(); | |
ushort MatShadPropParamB = f.ReadUInt16(); | |
ushort MatShadPropParamC = f.ReadUInt16(); | |
ushort MatShadPropUnk4 = f.ReadUInt16(); | |
ushort MatShadPropUnk5 = f.ReadUInt16(); | |
ushort MatShadPropUnk6 = f.ReadUInt16(); | |
ushort MatShadPropUnk7 = f.ReadUInt16(); | |
ushort MatShadPropUnk8 = f.ReadUInt16(); | |
ushort MatShadPropPointer = f.ReadUInt16(); | |
f.BaseStream.Seek(MatShadOffset + MatShadPropMatString, SeekOrigin.Begin); | |
long MatShadStringPtr = f.BaseStream.Position + f.ReadInt32(); | |
f.BaseStream.Seek(MatShadStringPtr, SeekOrigin.Begin); | |
int MatShadMatStringLen = f.ReadInt32(); | |
var MatShadMatString = new string(f.ReadChars(MatShadMatStringLen)); | |
Debug.Log("Textures used for " + MatShadMatString + ":"); | |
f.BaseStream.Seek(MatShadOffset + MatShadPropTexList, SeekOrigin.Begin); | |
long MatTexPtr = f.BaseStream.Position + f.ReadInt32(); | |
f.BaseStream.Seek(MatTexPtr, SeekOrigin.Begin); | |
int MatTexCount = f.ReadInt32(); | |
for (int y = 0; y < MatTexCount; y++) { | |
long MatTexOffset = f.BaseStream.Position + f.ReadInt32(); | |
long MatTexRet = f.BaseStream.Position; | |
f.BaseStream.Seek(MatTexOffset, SeekOrigin.Begin); | |
long MatTexLytPtr = f.BaseStream.Position - f.ReadInt32(); | |
f.BaseStream.Seek(MatTexLytPtr, SeekOrigin.Begin); | |
ushort MatTexLytHeadLen = f.ReadUInt16(); | |
ushort MatTexLytStrPtr = 0, MatTexLytHdrPtr = 0, MatTexLytIDPtr = 0, MatTexLytUnkPtr = 0; | |
switch (MatTexLytHeadLen) { | |
default: | |
throw new Exception("Unknown header length!"); | |
case 0x0A: | |
MatTexLytStrPtr = f.ReadUInt16(); | |
MatTexLytHdrPtr = f.ReadUInt16(); | |
MatTexLytIDPtr = f.ReadUInt16(); | |
MatTexLytUnkPtr = f.ReadUInt16(); | |
break; | |
} | |
f.BaseStream.Seek(MatTexOffset + MatTexLytStrPtr, SeekOrigin.Begin); | |
int MatTexStrLen = f.ReadInt32(); | |
var MatTexString = new string(f.ReadChars(MatTexStrLen)); | |
string MatTexID; | |
if (MatTexLytIDPtr != 0) { | |
f.BaseStream.Seek(MatTexOffset + MatTexLytIDPtr, SeekOrigin.Begin); | |
MatTexID = TexStringArray[f.ReadInt32()]; | |
} | |
else | |
MatTexID = TexStringArray[0]; | |
Debug.Log(MatTexString + ": " + MatTexID); | |
f.BaseStream.Seek(MatTexRet, SeekOrigin.Begin); | |
if (MatTexString == "Col0Tex" || MatTexString == "L0ColTex" || MatTexString == "Texture01" || MatTexString == "TextureMap01") | |
MatCol0 = MatTexID; | |
} | |
Debug.Log("--------------------"); | |
Debug.Log("Material properties for " + MatShadMatString + ":"); | |
f.BaseStream.Seek(MatShadOffset + MatShadPropParamA, SeekOrigin.Begin); | |
long MatPropAPtr = f.BaseStream.Position + f.ReadInt32(); | |
f.BaseStream.Seek(MatPropAPtr, SeekOrigin.Begin); | |
int MatPropACount = f.ReadInt32(); | |
for (int y = 0; y < MatPropACount; y++) { | |
long MatPropAStart = f.BaseStream.Position + f.ReadInt32(); | |
long MatPropRet = f.BaseStream.Position; | |
f.BaseStream.Seek(MatPropAStart, SeekOrigin.Begin); | |
long MatPropAPropPtr = f.BaseStream.Position - f.ReadInt32(); | |
f.BaseStream.Seek(MatPropAPropPtr, SeekOrigin.Begin); | |
ushort MatPropAHeadLen = f.ReadUInt16(); | |
ushort MatPropAStringPtr = 0, MatPropAFmtPtr = 0, MatPropAVarPtr = 0; | |
switch (MatPropAHeadLen) { | |
default: | |
throw new Exception("Unknown header length!"); | |
case 0x06: | |
MatPropAStringPtr = f.ReadUInt16(); | |
MatPropAFmtPtr = f.ReadUInt16(); | |
break; | |
case 0x08: | |
MatPropAStringPtr = f.ReadUInt16(); | |
MatPropAFmtPtr = f.ReadUInt16(); | |
MatPropAVarPtr = f.ReadUInt16(); | |
break; | |
} | |
f.BaseStream.Seek(MatPropAStart + MatPropAStringPtr, SeekOrigin.Begin); | |
int MatPropAStrLen = f.ReadInt32(); | |
var MatPropAString = new string(f.ReadChars(MatPropAStrLen)); | |
f.BaseStream.Seek(MatPropAStart + MatPropAFmtPtr, SeekOrigin.Begin); | |
int MatPropAFmt = f.ReadInt32(); | |
string MatPropAVar = "False"; | |
if (MatPropAVarPtr != 0) { | |
f.BaseStream.Seek(MatPropAStart + MatPropAVarPtr, SeekOrigin.Begin); | |
switch (MatPropAFmt) { | |
default: | |
throw new Exception("Unknown format!"); | |
case 4: | |
byte MatPropAVarByte = f.ReadByte(); | |
if (MatPropAVarByte == 1) | |
MatPropAVar = "True"; | |
break; | |
} | |
} | |
Debug.Log(MatPropAString + ": " + MatPropAVar); | |
f.BaseStream.Seek(MatPropRet, SeekOrigin.Begin); | |
} | |
f.BaseStream.Seek(MatShadOffset + MatShadPropParamB, SeekOrigin.Begin); | |
long MatPropBPtr = f.BaseStream.Position + f.ReadInt32(); | |
f.BaseStream.Seek(MatPropBPtr, SeekOrigin.Begin); | |
int MatPropBCount = f.ReadInt32(); | |
for (int y = 0; y < MatPropBCount; y++) { | |
long MatPropBStart = f.BaseStream.Position + f.ReadInt32(); | |
long MatPropRet = f.BaseStream.Position; | |
f.BaseStream.Seek(MatPropBStart, SeekOrigin.Begin); | |
long MatPropBPropPtr = f.BaseStream.Position - f.ReadInt32(); | |
f.BaseStream.Seek(MatPropBPropPtr, SeekOrigin.Begin); | |
ushort MatPropBHeadLen = f.ReadUInt16(); | |
ushort MatPropBStringPtr = 0, MatPropBFmtPtr = 0, MatPropBVarPtr = 0; | |
switch (MatPropBHeadLen) { | |
default: | |
throw new Exception("Unknown header length!"); | |
case 0x06: | |
MatPropBStringPtr = f.ReadUInt16(); | |
MatPropBFmtPtr = f.ReadUInt16(); | |
break; | |
case 0x08: | |
MatPropBStringPtr = f.ReadUInt16(); | |
MatPropBFmtPtr = f.ReadUInt16(); | |
MatPropBVarPtr = f.ReadUInt16(); | |
break; | |
} | |
f.BaseStream.Seek(MatPropBStart + MatPropBStringPtr, SeekOrigin.Begin); | |
int MatPropBStrLen = f.ReadInt32(); | |
var MatPropBString = new string(f.ReadChars(MatPropBStrLen)); | |
int MatPropBFmt = 0; | |
if (MatPropBFmtPtr != 0) { | |
f.BaseStream.Seek(MatPropBStart + MatPropBFmtPtr, SeekOrigin.Begin); | |
MatPropBFmt = f.ReadInt32(); | |
} | |
f.BaseStream.Seek(MatPropBStart + MatPropBVarPtr, SeekOrigin.Begin); | |
float MatPropBVar = 0; | |
if (MatPropBVarPtr != 0) { | |
switch (MatPropBFmt) { | |
default: | |
throw new Exception("Unknown format!"); | |
case 4: | |
MatPropBVar = f.ReadInt32(); | |
break; | |
case 8: | |
MatPropBVar = f.ReadSingle(); | |
break; | |
} | |
} | |
Debug.Log(MatPropBString + ": " + MatPropBVar); | |
switch (MatPropBString) { | |
case "ColorUVScaleU": | |
MatUVScaleU = MatPropBVar; | |
break; | |
case "ColorUVScaleV": | |
MatUVScaleV = MatPropBVar; | |
break; | |
case "ColorUVTranslateU": | |
MatUVTrsU = MatPropBVar; | |
break; | |
case "ColorUVTranslateV": | |
MatUVTrsV = MatPropBVar; | |
break; | |
case "Layer1UVScaleU": | |
MatUVScale2U = MatPropBVar; | |
break; | |
case "Layer1UVScaleV": | |
MatUVScale2V = MatPropBVar; | |
break; | |
case "Layer1UVTranslateU": | |
MatUVTrs2U = MatPropBVar; | |
break; | |
case "Layer1UVTranslateV": | |
MatUVTrs2V = MatPropBVar; | |
break; | |
case "L0ScaleU": | |
MatUVScaleU = MatPropBVar; | |
break; | |
case "L0ScaleV": | |
MatUVScaleV = MatPropBVar; | |
break; | |
case "L0UVTranslateU": | |
MatUVTrsU = MatPropBVar; | |
break; | |
case "L0UVTranslateV": | |
MatUVTrsV = MatPropBVar; | |
break; | |
case "L1ScaleU": | |
MatUVScale2U = MatPropBVar; | |
break; | |
case "L1ScaleV": | |
MatUVScale2V = MatPropBVar; | |
break; | |
case "L1UVTranslateU": | |
MatUVTrs2U = MatPropBVar; | |
break; | |
case "L1UVTranslateV": | |
MatUVTrs2V = MatPropBVar; | |
break; | |
case "Tex01_Scale_U": | |
MatUVScaleU = MatPropBVar; | |
break; | |
case "Tex01_Scale_V": | |
MatUVScaleV = MatPropBVar; | |
break; | |
case "Tex01_Translate_U": | |
MatUVTrsU = MatPropBVar; | |
break; | |
case "Tex01_Translate_V": | |
MatUVTrsV = MatPropBVar; | |
break; | |
case "Tex01_Rotate": | |
MatUVRot = MatPropBVar; | |
break; | |
case "Tex02_Scale_U": | |
MatUVScale2U = MatPropBVar; | |
break; | |
case "Tex02_Scale_V": | |
MatUVScale2V = MatPropBVar; | |
break; | |
case "Tex02_Translate_U": | |
MatUVTrs2U = MatPropBVar; | |
break; | |
case "Tex02_Translate_V": | |
MatUVTrs2V = MatPropBVar; | |
break; | |
case "Tex02_Rotate": | |
MatUVRot2 = MatPropBVar; | |
break; | |
} | |
f.BaseStream.Seek(MatPropRet, SeekOrigin.Begin); | |
} | |
f.BaseStream.Seek(MatShadOffset + MatShadPropParamC, SeekOrigin.Begin); | |
long MatPropCPtr = f.BaseStream.Position + f.ReadInt32(); | |
f.BaseStream.Seek(MatPropCPtr, SeekOrigin.Begin); | |
int MatPropCCount = f.ReadInt32(); | |
for (int y = 0; y < MatPropCCount; y++) { | |
long MatPropCStart = f.BaseStream.Position + f.ReadInt32(); | |
long MatPropRet = f.BaseStream.Position; | |
f.BaseStream.Seek(MatPropCStart, SeekOrigin.Begin); | |
long MatPropCPropPtr = f.BaseStream.Position - f.ReadInt32(); | |
f.BaseStream.Seek(MatPropCPropPtr, SeekOrigin.Begin); | |
ushort MatPropCHeadLen = f.ReadUInt16(); | |
ushort MatPropCStringPtr = 0, MatPropCFmtPtr = 0, MatPropCVarPtr = 0; | |
switch (MatPropCHeadLen) { | |
default: | |
throw new Exception("Unknown header length!"); | |
case 0x08: | |
MatPropCStringPtr = f.ReadUInt16(); | |
MatPropCFmtPtr = f.ReadUInt16(); | |
MatPropCVarPtr = f.ReadUInt16(); | |
break; | |
} | |
f.BaseStream.Seek(MatPropCStart + MatPropCStringPtr, SeekOrigin.Begin); | |
int MatPropCStrLen = f.ReadInt32(); | |
var MatPropCString = new string(f.ReadChars(MatPropCStrLen)); | |
int MatPropCFmt = 0; | |
if (MatPropCFmtPtr != 0) { | |
f.BaseStream.Seek(MatPropCStart + MatPropCFmtPtr, SeekOrigin.Begin); | |
MatPropCFmt = f.ReadInt32(); | |
} | |
f.BaseStream.Seek(MatPropCStart + MatPropCVarPtr, SeekOrigin.Begin); | |
float MatPropCVar1 = 0, MatPropCVar2 = 0, MatPropCVar3 = 0; | |
if (MatPropCVarPtr != 0) { | |
switch (MatPropCFmt) { | |
default: | |
throw new Exception("Unknown format!"); | |
case 4: | |
MatPropCVar1 = f.ReadSingle(); | |
MatPropCVar2 = f.ReadSingle(); | |
MatPropCVar3 = f.ReadSingle(); | |
break; | |
case 8: | |
MatPropCVar1 = f.ReadInt32(); | |
MatPropCVar2 = f.ReadInt32(); | |
MatPropCVar3 = f.ReadInt32(); | |
break; | |
} | |
} | |
Debug.Log(MatPropCString + ": " + MatPropCVar1.ToString() + " | " + MatPropCVar2.ToString() + " | " + MatPropCVar3.ToString()); | |
f.BaseStream.Seek(MatPropRet, SeekOrigin.Begin); | |
} | |
MatData_array.Add(new MatData_Struct { | |
MatName = MatShadMatString, | |
MatCol0 = MatCol0, | |
MatUVScaleU = MatUVScaleU, | |
MatUVScaleV = MatUVScaleV, | |
MatUVTrsU = MatUVTrsU, | |
MatUVTrsV = MatUVTrsV, | |
MatUVRot = MatUVRot, | |
MatUVScale2U = MatUVScale2U, | |
MatUVScale2V = MatUVScale2V, | |
MatUVTrs2U = MatUVTrs2U, | |
MatUVTrs2V = MatUVTrs2V, | |
MatUVRot2 = MatUVRot2 | |
}); | |
if (MatShadPropUnk1 != 0) { | |
f.BaseStream.Seek(MatShadOffset + MatShadPropUnk1, SeekOrigin.Begin); | |
MatShadPropUnk1 = f.ReadByte(); | |
} | |
if (MatShadPropUnk2 != 0) { | |
f.BaseStream.Seek(MatShadOffset + MatShadPropUnk2, SeekOrigin.Begin); | |
MatShadPropUnk2 = f.ReadByte(); | |
} | |
if (MatShadPropUnk3 != 0) { | |
f.BaseStream.Seek(MatShadOffset + MatShadPropUnk3, SeekOrigin.Begin); | |
MatShadPropUnk3 = f.ReadByte(); | |
} | |
if (MatShadPropParam1 != 0) { | |
f.BaseStream.Seek(MatShadOffset + MatShadPropParam1, SeekOrigin.Begin); | |
MatShadPropParam1 = f.ReadUInt16(); | |
} | |
if (MatShadPropParam2 != 0) { | |
f.BaseStream.Seek(MatShadOffset + MatShadPropParam2, SeekOrigin.Begin); | |
MatShadPropParam2 = f.ReadUInt16(); | |
} | |
if (MatShadPropParam3 != 0) { | |
f.BaseStream.Seek(MatShadOffset + MatShadPropParam3, SeekOrigin.Begin); | |
MatShadPropParam3 = f.ReadUInt16(); | |
} | |
if (MatShadPropParam4 != 0) { | |
f.BaseStream.Seek(MatShadOffset + MatShadPropParam4, SeekOrigin.Begin); | |
MatShadPropParam4 = f.ReadUInt16(); | |
} | |
if (MatShadPropParam5 != 0) { | |
f.BaseStream.Seek(MatShadOffset + MatShadPropParam5, SeekOrigin.Begin); | |
MatShadPropParam5 = f.ReadUInt16(); | |
} | |
if (MatShadPropParam6 != 0) { | |
f.BaseStream.Seek(MatShadOffset + MatShadPropParam6, SeekOrigin.Begin); | |
MatShadPropParam6 = f.ReadUInt16(); | |
} | |
if (MatShadPropUnk4 != 0) { | |
f.BaseStream.Seek(MatShadOffset + MatShadPropUnk4, SeekOrigin.Begin); | |
MatShadPropUnk4 = f.ReadByte(); | |
} | |
if (MatShadPropUnk5 != 0) { | |
f.BaseStream.Seek(MatShadOffset + MatShadPropUnk5, SeekOrigin.Begin); | |
MatShadPropUnk5 = f.ReadByte(); | |
} | |
if (MatShadPropUnk6 != 0) { | |
f.BaseStream.Seek(MatShadOffset + MatShadPropUnk6, SeekOrigin.Begin); | |
MatShadPropUnk6 = f.ReadByte(); | |
} | |
if (MatShadPropUnk7 != 0) { | |
f.BaseStream.Seek(MatShadOffset + MatShadPropUnk7, SeekOrigin.Begin); | |
MatShadPropUnk7 = f.ReadByte(); | |
} | |
if (MatShadPropUnk8 != 0) { | |
f.BaseStream.Seek(MatShadOffset + MatShadPropUnk8, SeekOrigin.Begin); | |
MatShadPropUnk8 = f.ReadByte(); | |
} | |
Debug.Log("Unknowns = BoolA: " + MatShadPropUnk1.ToString() + " | BoolB: " + MatShadPropUnk2.ToString() + " | BoolC: " + MatShadPropUnk3.ToString() + " | ValA: " + MatShadPropParam1.ToString() + " | ValB: " + MatShadPropParam2.ToString() + " | ValC: " + MatShadPropParam3.ToString() + " | ValD: " + MatShadPropParam4.ToString() + " | ValE: " + MatShadPropParam5.ToString() + " | ValF: " + MatShadPropParam6.ToString() + " | BoolD: " + MatShadPropUnk4.ToString() + " | BoolE: " + MatShadPropUnk5.ToString() + " | BoolF: " + MatShadPropUnk6.ToString() + " | BoolG: " + MatShadPropUnk7.ToString() + " | BoolH: " + MatShadPropUnk8.ToString()); | |
f.BaseStream.Seek(MatRet, SeekOrigin.Begin); | |
Debug.Log("--------------------"); | |
} | |
// Print mat data | |
foreach (var matData in MatData_array) | |
Debug.Log(matData.ToString()); | |
var multimat = new FbxSurfacePhong[MatNameCount]; | |
for (int m = 0; m < MatNameCount; m++) { | |
var matFileName = MatData_array[m].MatCol0 + ".png"; | |
var mat = multimat[m] = FbxSurfacePhong.Create(fbxManager, MatData_array[m].MatName); | |
mat.GetDefaultImplementation(); | |
var tm = FbxFileTexture.Create(fbxManager, matFileName); | |
tm.SetFileName(matFileName); | |
tm.SetAlphaSource(0); | |
mat.AmbientFactor.Set(0); | |
mat.DiffuseFactor.Set(0.8); | |
mat.Diffuse.ConnectSrcObject(tm); | |
mat.SpecularFactor.Set(2.5); | |
mat.ReflectionFactor.Set(0.5); | |
} | |
f.BaseStream.Seek(VertDataOffset, SeekOrigin.Begin); | |
int VertBufferCount = f.ReadInt32(); | |
for (int x = 0; x < VertBufferCount; x++) { | |
var Vert_array = new List<float[]>(); | |
var Normal_array = new List<float[]>(); | |
var Color_array = new List<byte[]>(); | |
var Alpha_array = new List<float>(); | |
var UV_array = new List<float[]>(); | |
var UV2_array = new List<float[]>(); | |
var UV3_array = new List<float[]>(); | |
var UV4_array = new List<float[]>(); | |
var Face_array = new List<ushort[]>(); | |
var FaceMatID_array = new List<int>(); | |
var B1_array = new List<Bone_Info_Struct>(); | |
var W1_array = new List<Weight_Info_Struct>(); | |
var Weight_array = new List<weight_data>(); | |
string PositionsFmt = "None"; | |
string NormalsFmt = "None"; | |
string TangentsFmt = "None"; | |
string UVsFmt = "None"; | |
string UVs2Fmt = "None"; | |
string UVs3Fmt = "None"; | |
string UVs4Fmt = "None"; | |
string ColorsFmt = "None"; | |
string Colors2Fmt = "None"; | |
string BonesFmt = "None"; | |
string WeightsFmt = "None"; | |
string BitangentsFmt = "None"; | |
int VertBufferStride = 0; | |
long VertBufferOffset = f.BaseStream.Position + f.ReadInt32(); | |
long VertBufferRet = f.BaseStream.Position; | |
f.BaseStream.Seek(VertBufferOffset, SeekOrigin.Begin); | |
Debug.Log("Vertex group " + x.ToString() + " start: " + f.BaseStream.Position.ToString()); | |
long VertLytPtr = f.BaseStream.Position - f.ReadInt32(); | |
f.BaseStream.Seek(VertLytPtr, SeekOrigin.Begin); | |
ushort VertLytHeadLen = f.ReadUInt16(); | |
if (VertLytHeadLen != 0x0A) | |
throw new Exception("Unknown header length!"); | |
var VertBuffVertPtr = f.ReadUInt16(); | |
var VertBuffPolyPtr = f.ReadUInt16(); | |
var VertBuffInfoPtr = f.ReadUInt16(); | |
var VertBuffUnkPtr = f.ReadUInt16(); | |
long VertBuffVertStart = VertBufferOffset + VertBuffVertPtr; | |
f.BaseStream.Seek(VertBufferOffset + VertBuffPolyPtr, SeekOrigin.Begin); | |
long VertBuffPolyStart = f.BaseStream.Position + f.ReadInt32(); | |
f.BaseStream.Seek(VertBufferOffset + VertBuffInfoPtr, SeekOrigin.Begin); | |
long VertBuffInfoStart = f.BaseStream.Position + f.ReadInt32(); | |
f.BaseStream.Seek(VertBuffInfoStart, SeekOrigin.Begin); | |
int VertInfoCount = f.ReadInt32(); | |
// Types: | |
// 0x00 = Positions | |
// 0x01 = Normals | |
// 0x02 = Tangents | |
// 0x03 = UVs(1) | |
// 0x04 = UVs(2) | |
// 0x05 = UVs(3) | |
// 0x06 = UVs(4) | |
// 0x07 = Colors | |
// 0x08 = Colors 2 | |
// 0x0B = Bone IDs | |
// 0x0C = Weights | |
// 0x0D = Bitangents | |
// Formats: | |
// 0x01 = Half-floats | |
// 0x02 = Floats | |
// 0x03 = Unsigned bytes | |
// 0x05 = Unsigned shorts | |
// 0x08 = Unsigned bytes as float (# / 255) | |
for (int v = 0; v < VertInfoCount; v++) { | |
long VertInfoOffset = f.BaseStream.Position + f.ReadInt32(); | |
long VertInfoRet = f.BaseStream.Position; | |
f.BaseStream.Seek(VertInfoOffset, SeekOrigin.Begin); | |
Debug.Log("Vertex format data " + v + " start: " + f.BaseStream.Position); | |
long VertInfoLytPtr = f.BaseStream.Position - f.ReadInt32(); | |
f.BaseStream.Seek(VertInfoLytPtr, SeekOrigin.Begin); | |
var VertInfoLytHeadLen = f.ReadUInt16(); | |
if (VertInfoLytHeadLen != 0x0A) | |
throw new Exception("Unknown header length!"); | |
var VertInfoLytSize = f.ReadUInt16(); | |
var VertInfoTypePtr = f.ReadUInt16(); | |
var VertInfoFmtPtr = f.ReadUInt16(); | |
var VertInfoUnkPtr = f.ReadUInt16(); | |
long VertBuffFmt = 0; | |
var VertBuffFmtString = ""; | |
if (VertInfoFmtPtr != 0x00) { | |
f.BaseStream.Seek(VertInfoOffset + VertInfoFmtPtr, SeekOrigin.Begin); | |
VertBuffFmt = f.ReadInt32(); | |
} | |
switch (VertBuffFmt) { | |
case 0: | |
VertBuffFmtString = "Floats"; | |
break; | |
case 1: | |
VertBuffFmtString = "Half-Floats"; | |
break; | |
case 3: | |
VertBuffFmtString = "Bytes"; | |
break; | |
case 5: | |
VertBuffFmtString = "Shorts"; | |
break; | |
case 8: | |
VertBuffFmtString = "BytesAsFloat"; | |
break; | |
default: | |
throw new Exception("Unknown vertex format detected!"); | |
} | |
var VertBuffType = 0; | |
if (VertInfoTypePtr != 0x00) { | |
f.BaseStream.Seek(VertInfoOffset + VertInfoTypePtr, SeekOrigin.Begin); | |
VertBuffType = f.ReadInt32(); | |
} | |
switch (VertBuffType) { | |
default: | |
throw new Exception("Unknown vertex type detected!"); | |
case 0: | |
PositionsFmt = VertBuffFmtString; | |
switch (VertBuffFmtString) { | |
default: | |
throw new Exception("Unknown positions combination detected!"); | |
case "Half-Floats": | |
VertBufferStride += 0x08; // Estimated | |
break; | |
case "Floats": | |
VertBufferStride += 0x0C; | |
break; | |
} | |
break; | |
case 1: | |
NormalsFmt = VertBuffFmtString; | |
switch (VertBuffFmtString) { | |
default: | |
throw new Exception("Unknown normals combination detected!"); | |
case "Half-Floats": | |
VertBufferStride += 0x08; | |
break; | |
case "Floats": | |
VertBufferStride += 0x0C; // Estimated | |
break; | |
} | |
break; | |
case 2: | |
TangentsFmt = VertBuffFmtString; | |
switch (VertBuffFmtString) { | |
default: | |
throw new Exception("Unknown tangents combination detected!"); | |
case "Half-Floats": | |
VertBufferStride += 0x08; | |
break; | |
case "Floats": | |
VertBufferStride += 0x0C; // Estimated | |
break; | |
} | |
break; | |
case 3: | |
UVsFmt = VertBuffFmtString; | |
switch (VertBuffFmtString) { | |
default: | |
throw new Exception("Unknown UV combination detected!"); | |
case "Half-Floats": | |
VertBufferStride += 0x04; | |
break; | |
case "Floats": | |
VertBufferStride += 0x08; | |
break; | |
} | |
break; | |
case 4: | |
UVs2Fmt = VertBuffFmtString; | |
switch (VertBuffFmtString) { | |
default: | |
throw new Exception("Unknown UV2 combination detected!"); | |
case "Half-Floats": | |
VertBufferStride += 0x04; | |
break; | |
case "Floats": | |
VertBufferStride += 0x08; | |
break; | |
} | |
break; | |
case 5: | |
UVs3Fmt = VertBuffFmtString; | |
switch (VertBuffFmtString) { | |
default: | |
throw new Exception("Unknown UV3 combination detected!"); | |
case "Half-Floats": | |
VertBufferStride += 0x04; | |
break; | |
case "Floats": | |
VertBufferStride += 0x08; | |
break; | |
} | |
break; | |
case 6: | |
UVs4Fmt = VertBuffFmtString; | |
switch (VertBuffFmtString) { | |
default: | |
throw new Exception("Unknown UV4 combination detected!"); | |
case "Half-Floats": | |
VertBufferStride += 0x04; | |
break; | |
case "Floats": | |
VertBufferStride += 0x08; | |
break; | |
} | |
break; | |
case 7: | |
ColorsFmt = VertBuffFmtString; | |
switch (VertBuffFmtString) { | |
default: | |
throw new Exception("Unknown colors combination detected!"); | |
case "Bytes": | |
VertBufferStride += 0x04; | |
break; | |
} | |
break; | |
case 8: | |
Colors2Fmt = VertBuffFmtString; | |
switch (VertBuffFmtString) { | |
default: | |
throw new Exception("Unknown colors 2 combination detected!"); | |
case "Bytes": | |
VertBufferStride += 0x04; | |
break; | |
} | |
break; | |
case 11: | |
BonesFmt = VertBuffFmtString; | |
switch (VertBuffFmtString) { | |
default: | |
throw new Exception("Unknown bones combination detected!"); | |
case "Shorts": | |
VertBufferStride += 0x08; | |
break; | |
case "Bytes": | |
VertBufferStride += 0x04; | |
break; | |
} | |
break; | |
case 12: | |
WeightsFmt = VertBuffFmtString; | |
switch (VertBuffFmtString) { | |
default: | |
throw new Exception("Unknown weights combination detected!"); | |
case "BytesAsFloat": | |
VertBufferStride += 0x04; | |
break; | |
} | |
break; | |
case 13: | |
BitangentsFmt = VertBuffFmtString; | |
switch (VertBuffFmtString) { | |
default: | |
throw new Exception("Unknown bitangents combination detected!"); | |
case "Half-Floats": | |
VertBufferStride += 0x08; | |
break; | |
} | |
break; | |
} | |
Debug.Log("Vertex format data " + v.ToString() + " end: " + f.BaseStream.Position.ToString()); | |
f.BaseStream.Seek(VertInfoRet, SeekOrigin.Begin); | |
} | |
Debug.Log("Stride: 0x" + VertBufferStride.ToString("X") + " | Normals: " + NormalsFmt + " | Tangents: " + TangentsFmt + " | UV1: " + UVsFmt + " | UV2: " + UVs2Fmt + " | UV3: " + UVs3Fmt + " | UV4: " + UVs4Fmt + " | Colors: " + ColorsFmt + " | Colors 2: " + Colors2Fmt + " | Bones: " + BonesFmt + " | Weights: " + WeightsFmt + " | Bitangents: " + BitangentsFmt); | |
f.BaseStream.Seek(VertBuffPolyStart, SeekOrigin.Begin); | |
int PolyBuffDatCount = f.ReadInt32(); | |
for (int p = 0; p < PolyBuffDatCount; p++) { | |
long PolyBuffDatOffset = f.BaseStream.Position + f.ReadInt32(); | |
long PolyRet = f.BaseStream.Position; | |
f.BaseStream.Seek(PolyBuffDatOffset, SeekOrigin.Begin); | |
Debug.Log("Facepoint " + p.ToString() + " data start: " + f.BaseStream.Position.ToString()); | |
long PolyLytPtr = f.BaseStream.Position - f.ReadInt32(); | |
f.BaseStream.Seek(PolyLytPtr, SeekOrigin.Begin); | |
short PolyLytHeadLen = f.ReadInt16(); | |
if (PolyLytHeadLen != 0x08) | |
throw new Exception("Unknown header length!"); | |
ushort PolyStartPtr = f.ReadUInt16(); | |
ushort PolyMatIDPtr = f.ReadUInt16(); | |
ushort PolyUnkPtr = f.ReadUInt16(); | |
var MatID = 0; | |
if (PolyMatIDPtr != 0x00) { | |
f.BaseStream.Seek(PolyBuffDatOffset + PolyMatIDPtr, SeekOrigin.Begin); | |
MatID = f.ReadInt32(); | |
} | |
f.BaseStream.Seek(PolyBuffDatOffset + PolyStartPtr, SeekOrigin.Begin); | |
int FacepointCount = f.ReadInt32(); | |
Debug.Log("Facepoint " + p.ToString() + " start: " + f.BaseStream.Position.ToString()); | |
for (int v = 0; v < (FacepointCount / 3); v++) { | |
ushort fa = f.ReadUInt16(); | |
ushort fb = f.ReadUInt16(); | |
ushort fc = f.ReadUInt16(); | |
Face_array.Add(new ushort[] { fa, fb, fc }); | |
FaceMatID_array.Add(MatID); | |
} | |
Debug.Log("Facepoint " + p.ToString() + " end: " + f.BaseStream.Position.ToString()); | |
f.BaseStream.Seek(PolyRet, SeekOrigin.Begin); | |
} | |
f.BaseStream.Seek(VertBuffVertStart, SeekOrigin.Begin); | |
int VertBufferSize = f.ReadInt32(); | |
Debug.Log("Vertex buffer " + x.ToString() + " start: " + f.BaseStream.Position.ToString()); | |
// Who needs a proper vertex count anyway am I right? | |
for (int v = 0; v < (VertBufferSize / VertBufferStride); v++) { | |
float vx, vy, vz, vq; | |
switch (PositionsFmt) { | |
default: | |
throw new Exception("Unknown positions type!"); | |
case "Half-Floats": | |
vx = ReadHalfFloat(f); | |
vy = ReadHalfFloat(f); | |
vz = ReadHalfFloat(f); | |
vq = ReadHalfFloat(f); | |
break; | |
case "Floats": | |
vx = f.ReadSingle(); | |
vy = f.ReadSingle(); | |
vz = f.ReadSingle(); | |
break; | |
} | |
float nx, ny, nz, nq; | |
switch (NormalsFmt) { | |
default: | |
throw new Exception("Unknown normals type!"); | |
case "Half-Floats": | |
nx = ReadHalfFloat(f); | |
ny = ReadHalfFloat(f); | |
nz = ReadHalfFloat(f); | |
nq = ReadHalfFloat(f); | |
break; | |
case "Floats": | |
nx = f.ReadSingle(); | |
ny = f.ReadSingle(); | |
nz = f.ReadSingle(); | |
break; | |
} | |
float binx, biny, binz, binq; | |
switch (TangentsFmt) { | |
default: | |
throw new Exception("Unknown tangents type!"); | |
case "None": | |
break; | |
case "Half-Floats": | |
binx = ReadHalfFloat(f); | |
biny = ReadHalfFloat(f); | |
binz = ReadHalfFloat(f); | |
binq = ReadHalfFloat(f); | |
break; | |
case "Floats": | |
binx = f.ReadSingle(); | |
biny = f.ReadSingle(); | |
binz = f.ReadSingle(); | |
break; | |
} | |
float tu, tv; | |
switch (UVsFmt) { | |
default: | |
throw new Exception("Unknown UV type!"); | |
case "None": | |
tu = 0; | |
tv = 0; | |
break; | |
case "Half-Floats": | |
tu = ReadHalfFloat(f); | |
tv = ReadHalfFloat(f); | |
break; | |
case "Floats": | |
tu = f.ReadSingle(); | |
tv = f.ReadSingle(); | |
break; | |
} | |
float tu2, tv2; | |
switch (UVs2Fmt) { | |
default: | |
throw new Exception("Unknown UV2 type!"); | |
case "None": | |
break; | |
case "Half-Floats": | |
tu2 = ReadHalfFloat(f); | |
tv2 = ReadHalfFloat(f); | |
UV2_array.Add(new float[] { tu2, tv2, 0 }); | |
break; | |
case "Floats": | |
tu2 = f.ReadSingle(); | |
tv2 = f.ReadSingle(); | |
UV2_array.Add(new float[] { tu2, tv2, 0 }); | |
break; | |
} | |
float tu3, tv3; | |
switch (UVs3Fmt) { | |
default: | |
throw new Exception("Unknown UV3 type!"); | |
case "None": | |
break; | |
case "Half-Floats": | |
tu3 = ReadHalfFloat(f); | |
tv3 = ReadHalfFloat(f); | |
UV3_array.Add(new float[] { tu3, tv3, 0 }); | |
break; | |
case "Floats": | |
tu3 = f.ReadSingle(); | |
tv3 = f.ReadSingle(); | |
UV3_array.Add(new float[] { tu3, tv3, 0 }); | |
break; | |
} | |
float tu4, tv4; | |
switch (UVs4Fmt) { | |
default: | |
throw new Exception("Unknown UV4 type!"); | |
case "None": | |
break; | |
case "Half-Floats": | |
tu4 = ReadHalfFloat(f); | |
tv4 = ReadHalfFloat(f); | |
UV4_array.Add(new float[] { tu4, tv4, 0 }); | |
break; | |
case "Floats": | |
tu4 = f.ReadSingle(); | |
tv4 = f.ReadSingle(); | |
UV4_array.Add(new float[] { tu4, tv4, 0 }); | |
break; | |
} | |
byte colorr, colorg, colorb; | |
float colora; | |
switch (ColorsFmt) { | |
default: | |
throw new Exception("Unknown color type!"); | |
case "None": | |
colorr = 255; | |
colorg = 255; | |
colorb = 255; | |
colora = 1; | |
break; | |
case "Bytes": | |
colorr = f.ReadByte(); | |
colorg = f.ReadByte(); | |
colorb = f.ReadByte(); | |
colora = f.ReadByte() / 255.0f; | |
break; | |
} | |
byte colorr2, colorg2, colorb2; | |
float colora2; | |
switch (Colors2Fmt) { | |
default: | |
throw new Exception("Unknown color 2 type!"); | |
case "None": | |
colorr2 = 255; | |
colorg2 = 255; | |
colorb2 = 255; | |
colora2 = 1; | |
break; | |
case "Bytes": | |
colorr2 = f.ReadByte(); | |
colorg2 = f.ReadByte(); | |
colorb2 = f.ReadByte(); | |
colora2 = f.ReadByte() / 255.0f; | |
break; | |
} | |
ushort Bone1, Bone2, Bone3, Bone4; | |
switch (BonesFmt) { | |
default: | |
throw new Exception("Unknown bones type!"); | |
case "None": | |
Bone1 = 1; | |
Bone2 = 0; | |
Bone3 = 0; | |
Bone4 = 0; | |
break; | |
case "Shorts": | |
Bone1 = f.ReadUInt16(); | |
Bone2 = f.ReadUInt16(); | |
Bone3 = f.ReadUInt16(); | |
Bone4 = f.ReadUInt16(); | |
break; | |
case "Bytes": | |
Bone1 = f.ReadByte(); | |
Bone2 = f.ReadByte(); | |
Bone3 = f.ReadByte(); | |
Bone4 = f.ReadByte(); | |
break; | |
} | |
float Weight1, Weight2, Weight3, Weight4; | |
switch (WeightsFmt) { | |
default: | |
throw new Exception("Unknown weights type!"); | |
case "None": | |
Weight1 = 1; | |
Weight2 = 0; | |
Weight3 = 0; | |
Weight4 = 0; | |
break; | |
case "BytesAsFloat": | |
Weight1 = f.ReadByte() / 255.0f; | |
Weight2 = f.ReadByte() / 255.0f; | |
Weight3 = f.ReadByte() / 255.0f; | |
Weight4 = f.ReadByte() / 255.0f; | |
break; | |
} | |
float tanx, tany, tanz, tanq; | |
switch (BitangentsFmt) { | |
default: | |
throw new Exception("Unknown bitangents type!"); | |
case "None": | |
break; | |
case "Half-Floats": | |
tanx = ReadHalfFloat(f); | |
tany = ReadHalfFloat(f); | |
tanz = ReadHalfFloat(f); | |
tanq = ReadHalfFloat(f); | |
break; | |
case "Floats": | |
tanx = f.ReadSingle(); | |
tany = f.ReadSingle(); | |
tanz = f.ReadSingle(); | |
break; | |
} | |
Vert_array.Add(new float[] { vx, vy, vz }); | |
Normal_array.Add(new float[] { nx, ny, nz }); | |
switch (VertColors) { | |
case VertexColor.Color1: | |
Color_array.Add(new byte[] { colorr, colorg, colorb }); | |
Alpha_array.Add(colora); | |
break; | |
case VertexColor.Color2: | |
Color_array.Add(new byte[] { colorr2, colorg2, colorb2 }); | |
Alpha_array.Add(colora2); | |
break; | |
} | |
UV_array.Add(new float[] { tu, tv, 0 }); | |
var w1 = new Weight_Info_Struct { Weight1 = Weight1, Weight2 = Weight2, Weight3 = Weight3, Weight4 = Weight4 }; | |
W1_array.Add(w1); | |
var b1 = new Bone_Info_Struct { Bone1 = Bone1, Bone2 = Bone2, Bone3 = Bone3, Bone4 = Bone4 }; | |
B1_array.Add(b1); | |
} | |
Debug.Log("Vertex buffer " + x.ToString() + " end: " + f.BaseStream.Position.ToString()); | |
f.BaseStream.Seek(VertBufferRet, SeekOrigin.Begin); | |
for (int b = 0; b < W1_array.Count; b++) { | |
var w = new weight_data { boneids = new List<int>(), weights = new List<float>() }; | |
float maxweight = 0; | |
if (W1_array[b].Weight1 != 0) | |
maxweight += W1_array[b].Weight1; | |
if (W1_array[b].Weight2 != 0) | |
maxweight += W1_array[b].Weight2; | |
if (W1_array[b].Weight3 != 0) | |
maxweight += W1_array[b].Weight3; | |
if (W1_array[b].Weight4 != 0) | |
maxweight += W1_array[b].Weight4; | |
if (maxweight != 0) { | |
if (W1_array[b].Weight1 != 0) { | |
float w1 = W1_array[b].Weight1; | |
w.boneids.Add(B1_array[b].Bone1); | |
w.weights.Add(w1); | |
} | |
if (W1_array[b].Weight2 != 0) { | |
float w2 = W1_array[b].Weight2; | |
w.boneids.Add(B1_array[b].Bone2); | |
w.weights.Add(w2); | |
} | |
if (W1_array[b].Weight3 != 0) { | |
float w3 = W1_array[b].Weight3; | |
w.boneids.Add(B1_array[b].Bone3); | |
w.weights.Add(w3); | |
} | |
if (W1_array[b].Weight4 != 0) { | |
float w4 = W1_array[b].Weight4; | |
w.boneids.Add(B1_array[b].Bone4); | |
w.weights.Add(w4); | |
} | |
} | |
Weight_array.Add(w); | |
} | |
// Mesh data | |
var meshNode = FbxNode.Create(fbxManager, VisGroupBone_array[x]); | |
var fbxMesh = FbxMesh.Create(fbxManager, VisGroupBone_array[x]); | |
// Asignar el mesh al nodo | |
meshNode.SetNodeAttribute(fbxMesh); | |
rootNode.AddChild(meshNode); | |
// Mats | |
foreach (var mat in multimat) | |
meshNode.AddMaterial(mat); | |
// Vertex | |
fbxMesh.InitControlPoints(Vert_array.Count); | |
for (int i = 0; i < Vert_array.Count; i++) { | |
var vertex = new FbxVector4(Vert_array[i][0], Vert_array[i][1], Vert_array[i][2]); | |
fbxMesh.SetControlPointAt(vertex, i); | |
} | |
// Face | |
for (int i = 0; i < Face_array.Count; i++) { | |
fbxMesh.BeginPolygon(); | |
for (int j = 0; j < Face_array[i].Length; j++) { | |
fbxMesh.AddPolygon(Face_array[i][j]); | |
} | |
fbxMesh.EndPolygon(); | |
} | |
// Get the fbx layer | |
var fbxLayer = fbxMesh.GetLayer(0); | |
if (fbxLayer == null) { | |
fbxMesh.CreateLayer(); | |
fbxLayer = fbxMesh.GetLayer(0); | |
} | |
// Normals | |
using (var normalElement = FbxLayerElementNormal.Create(fbxMesh, "Normals")) { | |
normalElement.SetMappingMode(FbxLayerElement.EMappingMode.eByControlPoint); | |
normalElement.SetReferenceMode(FbxLayerElement.EReferenceMode.eDirect); | |
var normalArray = normalElement.GetDirectArray(); | |
for (int v = 0; v < Normal_array.Count; v++) { | |
var na = Normal_array[v]; | |
var normal = new FbxVector4(na[0], na[1], na[2]); | |
normalArray.Add(normal); | |
} | |
fbxLayer.SetNormals(normalElement); | |
} | |
// Mats | |
using (var matElement = FbxLayerElementMaterial.Create(fbxMesh, "MatGroup")) { | |
matElement.SetMappingMode(FbxLayerElement.EMappingMode.eByPolygon); | |
matElement.SetReferenceMode(FbxLayerElement.EReferenceMode.eIndexToDirect); | |
var matArray = matElement.GetIndexArray(); | |
for (int v = 0; v < Face_array.Count; v++) | |
matArray.Add(FaceMatID_array[v]); | |
fbxLayer.SetMaterials(matElement); | |
} | |
// Vertex color | |
using (var colorElement = FbxLayerElementVertexColor.Create(fbxMesh, "VertexColors")) { | |
colorElement.SetMappingMode(FbxLayerElement.EMappingMode.eByControlPoint); | |
colorElement.SetReferenceMode(FbxLayerElement.EReferenceMode.eDirect); | |
var colorArray = colorElement.GetDirectArray(); | |
for (int i = 0; i < Color_array.Count; i++) { | |
var alpha = Alpha_array.ElementAtOrDefault(i); | |
colorArray.Add(new FbxColor(Color_array[i][0], Color_array[i][1], Color_array[i][2], alpha)); | |
} | |
fbxLayer.SetVertexColors(colorElement); | |
} | |
// Vertex color | |
using (var colorElement = FbxLayerElementVertexColor.Create(fbxMesh, "VertexColors2")) { | |
colorElement.SetMappingMode(FbxLayerElement.EMappingMode.eByControlPoint); | |
colorElement.SetReferenceMode(FbxLayerElement.EReferenceMode.eDirect); | |
var colorArray = colorElement.GetDirectArray(); | |
for (int i = 0; i < Color_array.Count; i++) { | |
var alpha = Alpha_array.ElementAtOrDefault(i); | |
colorArray.Add(new FbxColor(Color_array[i][0], Color_array[i][1], Color_array[i][2], alpha)); | |
} | |
fbxLayer.SetVertexColors(colorElement); | |
} | |
// UVs | |
void setUVs(List<float[]> uv_array, string uvName) { | |
if (uv_array == null || uv_array.Count == 0) | |
return; | |
using var uv = FbxLayerElementUV.Create(fbxMesh, uvName); | |
uv.SetMappingMode(FbxLayerElement.EMappingMode.eByControlPoint); | |
uv.SetReferenceMode(FbxLayerElement.EReferenceMode.eDirect); | |
var uvDirectArray = uv.GetDirectArray(); | |
for (int i = 0; i < uv_array.Count; i++) | |
uvDirectArray.Add(new FbxVector2(uv_array[i][0], uv_array[i][1])); | |
fbxLayer.SetUVs(uv); | |
} | |
setUVs(UV_array, "UVSet"); | |
setUVs(UV2_array, "UVSet2"); | |
setUVs(UV3_array, "UVSet3"); | |
setUVs(UV4_array, "UVSet4"); | |
// Skin | |
if (BoneRigArray.Count > 0) { | |
var skinMod = FbxSkin.Create(fbxMesh, fbxMesh.GetName() + "_skin"); | |
var fbxMeshMatrix = rootNode.EvaluateGlobalTransform(); | |
//s.Clear(); | |
// Añadir huesos al modificador de piel | |
for (int i = 0; i < BoneRigArray.Count; i++) { | |
var pair = BoneArray.FirstOrDefault(b => b.Value.GetName() == BoneRigArray[i]); | |
var bone = pair.Value;//BoneArray.Values.GetNodeByName(BoneRigArray[i]); | |
// Comprobar si se encontró el hueso | |
if (bone == null) { | |
Debug.LogError("No se encontró el hueso: " + BoneRigArray[i]); | |
continue; | |
} | |
// Create the deforming cluster | |
var fbxCluster = FbxCluster.Create(fbxScene, "BoneWeightCluster"); | |
fbxCluster.SetLink(bone); | |
fbxCluster.SetLinkMode(FbxCluster.ELinkMode.eTotalOne); | |
// set the Transform and TransformLink matrix | |
fbxCluster.SetTransformMatrix(fbxMeshMatrix); | |
var fbxLinkMatrix = bone.EvaluateGlobalTransform(); | |
fbxCluster.SetTransformLinkMatrix(fbxLinkMatrix); | |
// add the cluster to the skin | |
skinMod.AddCluster(fbxCluster); | |
} | |
// Añadir pesos a los vértices | |
for (int i = 0; i < Weight_array.Count; i++) { | |
var w = Weight_array[i]; | |
var boneIndexArray = w.boneids; | |
var weightValueArray = w.weights; | |
for (int j = 0; j < boneIndexArray.Count; j++) { | |
int boneIndex = boneIndexArray[j]; | |
var cluster = skinMod.GetCluster(boneIndex); | |
cluster.AddControlPointIndex(i, weightValueArray[j]); | |
} | |
} | |
// Añadir el modificador de piel a la malla | |
fbxMesh.AddDeformer(skinMod); | |
// Init bind pose | |
if (bindPose == null) { | |
bindPose = FbxPose.Create(fbxScene, "Default_BindPose"); | |
// set as bind pose | |
bindPose.SetIsBindPose(true); | |
// add the pose to the scene | |
fbxScene.AddPose(bindPose); | |
} | |
// Assign bind pose | |
foreach (var node in BoneArray.Values) | |
bindPose.Add(node, new FbxMatrix(node.EvaluateGlobalTransform())); | |
bindPose.Add(meshNode, new FbxMatrix(meshNode.EvaluateGlobalTransform())); | |
} | |
} | |
fbxManager.SetIOSettings(FbxIOSettings.Create(fbxManager, Globals.IOSROOT)); | |
var exporter = FbxExporter.Create(fbxManager, ""); | |
var fbxFormatStr = FBX_FORMTAT == FbxFormat.Binary ? "FBX binary (*.fbx)" : "FBX ascii (*.fbx)"; | |
var fileFormat = fbxManager.GetIOPluginRegistry().FindWriterIDByDescription(fbxFormatStr); | |
bool status = exporter.Initialize(fDir + "\\" + Path.GetFileNameWithoutExtension(g) + ".fbx", fileFormat, fbxManager.GetIOSettings()); | |
// Export if valid | |
if (status) | |
exporter.Export(fbxScene); | |
Debug.Log("Done! (" + Time.time + " Seconds)"); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment