Clustered Mesh

From Burnout Wiki
ClusteredMesh
aka CollisionMeshData

Track unit 203's clustered mesh.
Resource names Unknown
Type ID 0x24
Category Generic
Memory
distribution
Main Memory only
Imports Unknown
Imported by ID List
Editor
available?
Viewer only
Use Blender addons


Development
Information on versions of the Clustered Mesh resource type used during development.

Clustered Mesh resources were used for world collision (WORLDCOL) prior to the introduction of the Polygon Soup List resource type.

Structures

CgsPhysics::CollisionMeshData

32-bit

Offset Length Type Name Description Comments
0x0 0x4 Volume* mpCollisionVolume
0x4 0xC Padding
0x10 0x10 Vector3Plus mBoundingSphere

rw::collision::Volume

32-bit

Offset Length Type Name Description Comments
0x0 0x40 Matrix44Affine transform
0x40 0x4 Volume::VTable* vTable When written to file, this actually represents an rw::collision::VolumeType instead rather than a pointer. This is always VOLUMETYPEAGGREGATE, which has a value of 6.
0x44 0x4 ClusteredMesh* This is actually implemented as a 12-byte union accepting multiple types, including three floats representing triangles or boxes. The union type used is defined by the VolumeType in the vTable. The Clustered Mesh resource type however only accepts a ClusteredMesh pointer here (represented by the aggregate volume type), and will cause undefined behaviour if other types are used instead.
0x48 0x8 Union padding
0x50 0x4 float32_t radius
0x54 0x4 uint32_t groupID
0x58 0x4 uint32_t surfaceID
0x5C 0x4 uint32_t m_flags See VolumeFlag

rw::collision::VolumeFlag

Note that this is sourced from February 2007 data and may or may not have changed in later versions.

Name Value Comments
VOLUMEFLAG_ISENABLED 1
VOLUMEFLAG_TRIANGLENORMALISDIRTY 2
VOLUMEFLAG_TRIANGLEONESIDED 16 These precise values (but not the existence of the flags themselves) are technically platform-specific and is documented for PS3. It may or may not be actually different on other platforms.
VOLUMEFLAG_TRIANGLEEDGE0CONVEX 32
VOLUMEFLAG_TRIANGLEEDGE1CONVEX 64
VOLUMEFLAG_TRIANGLEEDGE2CONVEX 128
VOLUMEFLAG_TRIANGLEUSEEDGECOS 256
VOLUMEFLAG_TRIANGLEVERT0DISABLE 512
VOLUMEFLAG_TRIANGLEVERT1DISABLE 1024
VOLUMEFLAG_TRIANGLEVERT2DISABLE 2048
VOLUMEFLAG_FORCEENUMSIZEINT 0x7FFFFFFF

rw::collision::Aggregate

32-bit

Offset Length Type Name Description Comments
0x0 0x20 AABBox m_AABB
0x20 0x4 Aggregate::VTable* m_vTable Garbage data in the file - always replaced on read
0x24 0x4 uint32_t m_numTagBits
0x28 0x4 uint32_t m_numVolumes
0x2C 0x4 uint32_t pad

rw::collision::Procedural

32-bit

Offset Length Type Name Description Comments
0x0 0x30 Aggregate Base class

rw::collision::ClusteredMesh

The base pointer resets here - all pointer offsets here are relative to the start of this struct.

32-bit

Offset Length Type Name Description Comments
0x0 0x30 Procedural Base class
0x30 0x4 KDTree* mKDTree
0x34 0x4 uint32_t* mCluster Effectively a ClusteredMeshCluster**
0x38 0x8 ClusterParams mClusterParams
0x40 0x4 uint32_t mNumClusters
0x44 0x4 uint32_t mMaxClusters
0x48 0x4 uint32_t mNumUnits
0x4C 0x4 uint32_t mMaxUnits
0x50 0x4 uint32_t mSizeOfThis
0x54 0x2 uint16_t mDefaultGroupId
0x56 0x2 uint16_t mDefaultSurfaceId
0x58 0x1 uint8_t mDefaultEdgeAngle
0x59 0x7 Padding

rw::collision::AALineClipper::AABBox

Offset Length Type Name Description Comments
0x0 0x10 vpu::Vector3 m_min
0x10 0x10 vpu::Vector3 m_max

rw::collision::ClusterParams

Offset Length Type Name Description Comments
0x0 0x4 float32_t mVertexCompressionGranularity Relevant for cluster compression modes 1 and 2
0x4 0x2 uint16_t mFlags Likely CMFlags
0x6 0x1 uint8_t mGroupIdSize Number of bytes 1 or 2
0x7 0x1 uint8_t mSurfaceIdSize Number of bytes 1 or 2

rw::collision::CMFlags

Note that this is sourced from February 2007 data and may or may not have changed in later versions.

Name Value Comments
CMFLAG_INT16VERTEX 1
CMFLAG_INT16NORMAL 2
CMFLAG_20BITCLUSTERINDEX 4
CMFLAG_ONESIDED 16
CMFLAG_FORCEENUMSIZEINT 0x7FFFFFFF

rw::collision::KDTree

The base pointer resets here - all pointer offsets here are relative to the start of this struct.

32-bit

Offset Length Type Name Description Comments
0x0 0x4 BranchNode* m_branchNodes
0x4 0x4 uint32_t m_numBranchNodes
0x8 0x4 uint32_t m_numEntries
0xC 0x4 Padding
0x10 0x20 AABBox m_bbox

rw::collision::KDTree::BranchNode

Offset Length Type Name Description Comments
0x0 0x4 uint32_t m_parent
0x4 0x4 uint32_t m_axis
0x8 0x10 NodeRef[2] m_childRefs
0x18 0x8 float32_t[2] m_extents

rw::collision::KDTree::NodeRef

Offset Length Type Name Description Comments
0x0 0x4 uint32_t m_content
0x4 0x4 uint32_t m_index

rw::collision::ClusteredMeshCluster

Offset Length Type Name Description Comments
0x0 0x2 uint16_t unitCount
0x2 0x2 uint16_t unitDataSize
0x4 0x2 uint16_t unitDataStart The index of the vertex array where unit data starts
0x6 0x2 uint16_t normalStart The index of the vertex array where normal data starts
0x8 0x2 uint16_t totalSize
0xA 0x1 uint8_t vertexCount
0xB 0x1 uint8_t normalCount
0xC 0x1 uint8_t compressionMode VERTICES_UNCOMPRESSED = 0
VERTICES_16BIT_COMPRESSED = 1
VERTICES_32BIT_COMPRESSED = 2
0xD 0x3 uint8_t[3] Padding
0x10 0x10 vpu::Vector3[1] vertexArray Variable size data
Hmmm...
Hmmm...
To do:
Normals?
Vertex data
Unit data

Vertex data

VERTICES_UNCOMPRESSED
Offset Length Type Name Comments
0x0
(repeating)
0x10 vpu::Vector3 Raw vector (mVertexCompressionGranularity unused)
VERTICES_16BIT_COMPRESSED
Offset Length Type Name Comments
0x0 0xC int32_t[3] vertexOffsetData Component base
0xC
(repeating)
0x6 Vertex16[3] vertData Add to initial int32_t components and then multiply components by mVertexCompressionGranularity to get coordinate
VERTICES_32BIT_COMPRESSED
Offset Length Type Name Comments
0x0
(repeating)
0xC Vertex32[3] vertData Multiply components by mVertexCompressionGranularity to get coordinate
rw::collision::ClusteredMeshCluster::Vertex16
Offset Length Type Name
0x0 0x2 uint16_t x
0x2 0x2 uint16_t y
0x4 0x2 uint16_t z
rw::collision::ClusteredMeshCluster::Vertex32
Offset Length Type Name
0x0 0x4 int32_t x
0x4 0x4 int32_t y
0x8 0x4 int32_t z

Unit data

This is a byte stream. Exact offsets are variable and depends on several factors, as detailed below.

Length Type Description Comments
0x1 uint8_t Lower nibble (type)
[unused] UNITTYPE_OLDTRIANGLE = 0
UNITTYPE_TRIANGLE = 1
UNITTYPE_QUAD = 2
UNITTYPE_TRILIST = 3
Upper nibble (flags)
UNITFLAG_NORMAL = 1
UNITFLAG_EDGEANGLE = 2
UNITFLAG_GROUPID = 4
UNITFLAG_SURFACEID = 8
[unused] UNITFLAG_USEOLDTRI = all bits set (including type)
0x1 uint8_t Only present if type == UNITTYPE_TRILIST
Triangle count
For UNITTYPE_OLDTRIANGLE/UNITTYPE_TRIANGLE this is implicitly 1 and for UNITTYPE_QUAD this is implicitly 2
Vertex count
(triangle count + 2)
uint8_t Vertex index
0x1 uint8_t Only present with UNITFLAG_NORMAL
Normal index probably
Edge count
(triangle count + 2)
uint8_t Only present with UNITFLAG_EDGEANGLE Edge cosines? Mask with 0x1F and flags above that? rw::colison::UnitEdgeFlags is likely relevant
Group ID size (see ClusterParams) uint8_t or uint16_t Only present with UNITFLAG_GROUPID
Group ID
This is always little endian.
Surface ID size (see ClusterParams) uint8_t or uint16_t Only present with UNITFLAG_SURFACEID
Surface ID
This is always little endian.