PBA
Appearance
Warning
WIP Page, just adding to start

chr_sage.pba
contains a node for a cloth mesh made up of only vertices and edges, interconnected in such a way to maintain shape with internal springsPBA files are bone physics files first found in Sonic Frontiers, and first regularly used in Shadow Generations. The system is capable of using bouncy bones/jiggle physics, rag-doll physics, and cloth simulation. The format is still relatively unknown and has only been brute forced through hex analysis more than code analysis, and there are unfortunately not many examples files to reference. The below template has lots of unknowns and potentially wrong info.
Binary Structure
TODO: Decipher, clean up, explain 0_0
//------------------------------------------------
//--- 010 Editor v12.0.1 Binary Template
//
// File:
// Authors: Ashrindy, AdelQ
// Version: 0.0.1
// Purpose: Shadow Gens PhysicalSkeleton
// Category:
// File Mask: *.pba
// ID Bytes:
// History:
//------------------------------------------------
#include "../include.h"
local uint64 dataPos;
typedef struct{
Vector4 rows[4];
}Matrix4x4<optimize=false>;
typedef struct{
byte UnkB1; // Always 2 or 1, unknown flag
byte UnkB2; // Always 0 or 1, unknown flag
byte UnkB3[2]; // Padding?
float Unk_f[4]; // Upper/Lower limits of something?
}LimitsStruct<optimize=false>;
typedef struct{
SetRandomBackColor();
StringOffset BoneName;
int unk; // if this is related to collision, this could be an enum for the collision shape
float unk2; // Physics dampening? Lower values make bones wobble for longer
Matrix4x4 mat; // Most likely not a matrix, has parameters that affect gravity, stretch, etc, and possibly capsule/collision bounds(?) but still working through
}CollisionStruct<optimize=false>; // Has params that affect physics intensity still, maybe general physics
typedef struct{
SetRandomBackColor();
StringOffset BoneName;
byte Unk1[4]; // All known examples are 01 01 14 00. could be bitflags by the looks of it
int16 LocalParentBoneIndex; // FF FF if no bone parent
int16 LocalBoneIndex;
int16 RealParentBoneIndex; // Usually the parent of this bone on the real skeleton, but can be any bone in practice. Perhaps a reference for the offset transform?
int16 Unk3;
LimitsStruct Limits[6]; // Unknown what these limits line up to (Pos to Neg X, Pos to Neg Y, etc)
float Unk4<hidden=true>; // Align
Matrix4x4 mat; // Possibly bone offset matrix relative to RealParentBoneIndex? A: Two quaternions in row 2 and 4?
}
JiggleStruct<optimize=false>; // Handles bone chain relations for bendy/jiggle physics, as well as presumably transform limits
typedef struct{
// Starting point needs to align to 16 bytes
local uint64 CurPos = FTell();
local uint64 AlignCheck = CurPos % 0x10;
if (AlignCheck)
FSeek(CurPos + 0x10 - AlignCheck);
SetRandomBackColor();
StringOffset BoneName;
float unk0; // All known examples = 0.01
int16 unk1<hidden=true>; // Always FF FF
int16 if_pinned; // 1 if no parent present. Possibly this bone controls corresponding vertex if 1, versus vertex controls cooresponding bone if 0
int16 child_idx; // FF if no child
int16 parent_idx; // FF if no parent
int16 unk2[2]<hidden=true>; // Always FF FF
int16 left_idx;
int16 right_idx;
}cloth_node<optimize=false>; // Defines up to 4 neighboring bones in a cloth bone grid
typedef struct{
SetRandomBackColor();
int16 verts[2];
float edge_length;
float unk_factor; // Normalized, lateral direct connections = 0.5, lateral skip connections = 0.3, vertical direct connections = 1.0. Maybe a stretch/shrink factor?
}cloth_edges<optimize=false>; // Cloth sim edge mesh
typedef struct{
SetRandomBackColor();
StringOffset cloth_name;
float unk1[10];
int16 unk_count1[2];
int32 cloth_node_count;
int32 cloth_edge_count;
int32 unk3<hidden=true>; // Align
int64 cloth_node_ptr;
int64 cloth_edge_ptr;
local int64 prePos = FTell();
FSeek(cloth_node_ptr + dataPos);
cloth_node bones[cloth_node_count];
FSeek(cloth_edge_ptr + dataPos);
cloth_edges edges[cloth_edge_count];
FSeek(prePos);
}ClothStruct<optimize=false>;
typedef struct{
SetRandomBackColor();
char signature[4]<name="Signature">;
int version <format=hex, name="Version">;
StringOffset SkeletonName;
uint32 CollisionCount;
uint32 JiggleCount;
uint64 CollisionOffset;
uint64 JiggleOffset;
uint32 ClothCount;
uint32 UnkCount;
uint64 ClothOffset;
uint64 UnkOffset;
FSeek(CollisionOffset + dataPos);
CollisionStruct CollisionStructs[CollisionCount];
FSeek(JiggleOffset + dataPos);
JiggleStruct JiggleStructs[JiggleCount];
FSeek(ClothOffset + dataPos);
ClothStruct ClothStructs[ClothCount];
}
ResPhysicalSkeleton<open=true>;
ResBinaryFile file("ResPhysicalSkeleton")<name=Str("%s", FileNameGetBase(GetFileName()))>;