Skip to content

Latest commit

 

History

History
1118 lines (1073 loc) · 23.8 KB

README.md

File metadata and controls

1118 lines (1073 loc) · 23.8 KB

Cast | An open-source container for models, animations, and more

The goal of cast is to create an easy to use format for models, animations, materials, and game worlds. In addition, cast should be able to produce the same scenes in any 3d software.

Cast

3D Engine Plugins:

Programming libraries:

Viewers:

  • CastModelViewer (By echo000): Github

Coming from SEAnim/SEModel:

  • SECast, a lossless converter to cast: SECast
  • Note: If your tool supports exporting to cast directly, that is always better.

FAQ:

  • Frequently asked questions: FAQ

File stucture:

All files start with a cast header:

struct CastHeader
{
	uint32_t Magic;			// char[4] cast	(0x74736163)
	uint32_t Version;		// 0x1
	uint32_t RootNodes;		// Number of root nodes, which contain various sub nodes if necessary
	uint32_t Flags;			// Reserved for flags, or padding, whichever is needed
};

A cast file is basically a group of generic nodes. Nodes are given a unique registered id, which can tell the loader what the data is, and how to handle it.

Following the cast header is a collection of nodes which must be of type CastId::Root.

A node looks like:

struct CastNodeHeader
{
	CastId Identifier;		// Used to signify which class this node uses
	uint32_t NodeSize;		// Size of all data and sub data following the node
	uint64_t NodeHash;		// Unique hash, like an id, used to link nodes together
	uint32_t PropertyCount;	// The count of properties
	uint32_t ChildCount;	// The count of direct children nodes

	// We must read until the node size hits, and that means we are done.
	// The nodes are in a stack layout, so it's easy to load, FILO order.
};

There are several registered cast ids available:

enum class CastId : uint32_t
{
	Root = 0x746F6F72,
	Model = 0x6C646F6D,
	Mesh = 0x6873656D,
	BlendShape = 0x68736C62,
	Skeleton = 0x6C656B73,
	Bone = 0x656E6F62,
	IKHandle = 0x64686B69,
	Constraint = 0x74736E63,
	Animation = 0x6D696E61,
	Curve = 0x76727563,
	CurveModeOverride = 0x564F4D43,
	NotificationTrack = 0x6669746E,
	Material = 0x6C74616D,
	File = 0x656C6966,
	Instance = 0x74736E69,
	Metadata = 0x6174656D,
};

Following a node, is the list of properties [Node.PropertyCount], a property looks like:

struct CastPropertyHeader
{
	CastPropertyId Identifier;	// The element type of this property
	uint16_t NameSize;			// The size of the name of this property
	uint32_t ArrayLength;		// The number of elements this property contains (1 for single)

	// Following is UTF-8 string lowercase, size of namesize, NOT null terminated
	// cast_property[ArrayLength] array of data
};

For properties, cast has several built in types:

enum class CastPropertyId : uint16_t
{
	Byte = 'b',			// <uint8_t>
	Short = 'h',		// <uint16_t>
	Integer32 = 'i',	// <uint32_t>
	Integer64 = 'l',	// <uint64_t>

	Float = 'f',		// <float>
	Double = 'd',		// <double>

	String = 's',		// Null terminated UTF-8 string

	Vector2 = 'v2',		// Float precision vector XY
	Vector3 = 'v3',		// Float precision vector XYZ
	Vector4 = 'v4'		// Float precision vector XYZW
};

Parsing

To read a cast file, you just need to traverse the root nodes and their children. Properties always come before a nodes children. Each node has the total size of itself, and all children, so if a processor doesn't understand a node id, it can skip the entire node and continue reading.

Cast ids are stored as integers to make it faster to serialize and deserialize.

Cast processors:

Model:

Field Type(s) IsArray Required
Children Skeleton, Mesh, Material True False
Parent Root False True
Property (id) Type(s) IsArray Required
Name (n) String (s) False False

Mesh:

Field Type(s) IsArray Required
Children None True False
Parent Model False True
Property (id) Type(s) IsArray Required
Name (n) String (s) False False
Vertex Position Buffer (vp) Vector 3 (v3) True True
Vertex Normal Buffer (vn) Vector 3 (v3) True False
Vertex Tangent Buffer (vt) Vector 3 (v3) True False
Vertex Color Buffer (c%d) Integer 32 (i) True False
Vertex UV Buffer (u%d) Vector 2 (v2) True False
Vertex Weight Bone Buffer (wb) Integer 32 (i), Short (h), Byte (b) True False
Vertex Weight Value Buffer (wv) Float (f) True False
Face Buffer (f) Integer 32 (i), Short (h), Byte (b) True True
Color Layer Count (cl) Integer 32 (i), Short (h), Byte (b) False True if has color layers else False
UV Layer Count (ul) Integer 32 (i), Short (h), Byte (b) False True if has uv layers else False
Maximum Weight Influence (mi) Integer 32 (i), Short (h), Byte (b) False True if has weights else False
Skinning Method (sm) String (s) [linear, quaternion] False False
Material (Hash of CastNode:Material) (m) Integer 64 (l) False False

Notes:

  • Face Buffer is an index into the current meshes vertex data buffers where (0, 1, 2) are the first three vertices from this mesh.
  • The Face Buffer follows CCW (right-handed) winding order, this may be different in other apis, where you may have to remap the indices.
  • If a face contains an invalid index combination (0, 1, 1), (0, 1, 0), (0, 0, 0) where two or more indices are the same, it is acceptable for the user processing these faces to ignore them in order to properly render the mesh. It would be wise to present the user with a warning stating that this happened.
  • Each vertex descriptor buffer must contain the same number of elements ex: if you have 16 vertices, you must have 16 normals if they exist, 16 colors if the buffer exists. Otherwise it's assumed they are default / skipped.
  • Weights are additive which means having the same bone with 0.5 and 0.5 would end up making that bones influence 1.0 for example.
  • The default skinning method is linear. When set to quaternion dual quaternion skinning is used.
  • NEW 8/18/2024: The vertex color specification has changed, in order to support multiple color layers, a new Color Layer Count (cl) was added which mimics the UV Layer Count (ul) property.
    • To be backwards compatible, cast processors should check for cl, and use that by default along with the new c%d layer properties.
    • If the cl property does not exist, a processor should check for the legacy vc property which is the one and only color layer if it exists.

Blend Shape:

Field Type(s) IsArray Required
Children None True False
Parent Model False True
Property (id) Type(s) IsArray Required
Name (n) String (s) False True
Base Shape (Hash of CastNode:Mesh) (b) Integer 64 (l) False True
Target Shape Vertex Indices (vi) Byte (b), Short (h), Integer 32 (i) True True
Target Shape Vertex Positions (vp) Vector 3 (v3) True True
Target Weight Scale (ts) Float (f) True False

Notes:

  • The Base Shape must be an existing cast mesh.
  • The Target Shape Vertex Indices and Target Shape Vertex Positions must be the same length as they are paired together.
  • Target Shape Vertex Positions is the final value of each changed vertex position ignoring the Base Shape's corresponding vertex.
  • Target Weight Scale indicates the maximum value the target shape can deform to and should default to 1.0.

Skeleton:

Field Type(s) IsArray Required
Children Bone, IKHandle, Constraint True False
Parent Model False True

Bone:

Field Type(s) IsArray Required
Children None True False
Parent Skeleton False True
Property (id) Type(s) IsArray Required
Name (n) String (s) False True
Parent Index (p) Integer 32 (i) False False
Segment Scale Compensate (ssc) Byte (b) [True, False] False False
Local Position (lp) Vector 3 (v3) False False
Local Rotation (lr) Vector 4 (v4) False False
World Position (wp) Vector 3 (v3) False False
World Rotation (wr) Vector 4 (v4) False False
Scale (s) Vector 3 (v3) False False

Notes:

  • Segment Scale Compensate should default to True when not specified.
  • Scale is always local to the current bone.

IKHandle:

Field Type(s) IsArray Required
Children None True False
Parent Skeleton False True
Property (id) Type(s) IsArray Required
Name (n) String (s) False False
Start Bone Hash (sb) Integer 64 (l) False True
End Bone Hash (eb) Integer 64 (l) False True
Target Bone Hash (tb) Integer 64 (l) False False
Pole Vector Bone Hash (pv) Integer 64 (l) False False
Pole Bone Hash (pb) Integer 64 (l) False False
Use Target Rotation (tr) Byte (b) [True, False] False False

Notes:

  • Use Target Rotation should default to False when not specified.
  • Pole Bone must only effect the twist of the chain, in general you either have a Pole Bone or a Pole Vector Bone.

Constraint:

Field Type(s) IsArray Required
Children None True False
Parent Skeleton False True
Property (id) Type(s) IsArray Required
Name (n) String (s) False False
Constraint Type (ct) String (s) [pt, or, sc] False True
Constraint Bone Hash (cb) Integer 64 (l) False True
Target Bone Hash (tb) Integer 64 (l) False True
Maintain Offset (mo) Byte (b) [True, False] False False
Skip X (sx) Byte (b) [True, False] False False
Skip Y (sy) Byte (b) [True, False] False False
Skip Z (sz) Byte (b) [True, False] False False

Notes:

  • The constraint type values correspond to:
    • pt Point Constraint, which applies to translations.
    • or Orient Constraint, which applies to rotations.
    • sc Scale Constraint, which applies to scales.
  • Maintain offset should default to False when not specified.
  • Skip X, Skip Y, and Skip Z should default to False when not specified and refer to ignoring that axis in the constraint.

Material:

Field Type(s) IsArray Required
Children File True False
Parent Model False True
Property (id) Type(s) IsArray Required
Name (n) String (s) False True
Type (t) String (s) False True
Albedo File Hash (albedo) Integer 64 (l) False False
Diffuse File Hash (diffuse) Integer 64 (l) False False
Normal File Hash (normal) Integer 64 (l) False False
Specular File Hash (specular) Integer 64 (l) False False
Emissive File Hash (emissive) Integer 64 (l) False False
Gloss File Hash (gloss) Integer 64 (l) False False
Roughness File Hash (roughness) Integer 64 (l) False False
Ambient Occlusion File Hash (ao) Integer 64 (l) False False
Cavity File Hash (cavity) Integer 64 (l) False False
Anisotropy File Hash (aniso) Integer 64 (l) False False
Extra (x) File Hash (extra%d) Integer 64 (l) False False

File:

Field Type(s) IsArray Required
Children None True False
Parent CastNode False True
Property (id) Type(s) IsArray Required
Path (p) String (s) False True

Animation:

Field Type(s) IsArray Required
Children Skeleton, Curve, CurveModeOverride, NotificiationTrack True True
Parent Root False True
Property (id) Type(s) IsArray Required
Name (n) String (s) False False
Framerate (fr) Float (f) False True
Looping (lo) Byte (b) [True, False] False False

Curve:

Field Type(s) IsArray Required
Children None True False
Parent Animation False True
Property (id) Type(s) IsArray Required
Node Name (nn) String (s) False True
Key Property Name (kp) String (s) [rq, tx, ty, tz, sx, sy, sz, bs, vb] False True
Key Frame Buffer (kb) Byte (b), Short (h), Integer 32 (i) True True
Key Value Buffer (kv) Byte (b), Short (h), Integer 32 (i), Float (f), Vector 4 (v4) True True
Mode (m) String (s) [additive, absolute, relative] False True
Additive Blend Weight (ab) Float (f) False False

Notes:

  • All curve keyframes are in object/node space.
  • The Mode determines how each curve keyframe is applied to the node.
    • additive: The keyframe is added to the current scene frame value of the nodes property.
    • absolute: The keyframe is the exact value for the given frame.
    • relative: The keyframe is added to the rest position value of the nodes property.
  • The property values correspond to:
    • rq Rotation Quaternion and expects v4 values.
    • tx Translation 'X' and expects f values.
    • ty Translation 'Y' and expects f values.
    • tz Translation 'Z' and expects f values.
    • sx Scale 'X' and expects f values.
    • sy Scale 'Y' and expects f values.
    • sz Scale 'Z' and expects f values.
    • bs BlendShape Weight and expects f values.
    • vb Visibility and expects b, h, or i values.
      • =0 = hidden.
      • >=1 = visible.
  • The properties tx, ty, tz, sx, sy, sz, bs, vb should interpolate linearly.
  • The property rq should interpolate with quaternion slerp.

CurveModeOverride:

Field Type(s) IsArray Required
Children None True False
Parent Animation False True
Property (id) Type(s) IsArray Required
Node Name (nn) String (s) False True
Mode (m) String (s) [additive, absolute, relative] False True
Override Translation Curves (ot) Byte (b) [True, False] False False
Override Rotation Curves (or) Byte (b) [True, False] False False
Override Scale Curves (os) Byte (b) [True, False] False False

Notes:

  • See Curve notes above for the definition of each Mode value.
  • Override Translation Curves should default to False when not specified.
  • Override Rotation Curves should default to False when not specified.
  • Override Scale Curves should default to False when not specified.
  • The override node and all of it's children should override their curves mode to the new mode.
  • The override node must be present at the time of processing in order to determine if a child bone is a descendent.

NotificationTrack:

Field Type(s) IsArray Required
Children None True False
Parent Animation False True
Property (id) Type(s) IsArray Required
Name (n) String (s) False True
Key Frame Buffer (kb) Byte (b), Short (h), Integer 32 (i) True True

Instance:

Field Type(s) IsArray Required
Children File True False
Parent Root False True
Property (id) Type(s) IsArray Required
Name (n) String (s) False False
Reference File (Hash of CastNode:File) (rf) Integer 64 (l) False True
Position (p) Vector 3 (v3) False True
Rotation (r) Vector 4 (v4) False True
Scale (s) Vector 3 (v3) False True

Metadata:

Field Type(s) IsArray Required
Children None True False
Parent Root False True
Property (id) Type(s) IsArray Required
Author (a) String (s) False False
Software (s) String (s) False False
Up Axis (up) String (s) [x, y, z] False False

Notes:

  • Author and Software are just for tagging cast files and have no use outside of metadata.
  • Up Axis can be used as a hint to software to adjust the scene to match a specific up axis.
  • A cast file can have any number of meta nodes but properties designed for hinting should only use the first metadata node instance.

  • Format designed by DTZxPorter with input from the community.
  • Icons by Smashicons