Skip to content

Instantly share code, notes, and snippets.

@TitanX101
Last active January 31, 2025 18:31
Show Gist options
  • Save TitanX101/304d131534ecc134bccca5467372c5cb to your computer and use it in GitHub Desktop.
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…
// 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