Actions

SCHG

Difference between revisions of "Sonic Heroes/Collision Format"

From Sonic Retro

Line 1: Line 1:
 
{{SCHG SH}}
 
{{SCHG SH}}
  
Level collision in Sonic Heroes is defined in big endian .cl files located in dvdroot/collisions in the PC version. These files are not RenderWare collision files and are the same between different versions of the game. They use a quadtree based system to optimize collision detection. s*.cl files contain normal level collision, s*_xx.cl files contain collision for death boundaries and s*_wt.cl files contain water boundaries. The s*.cl file is required for the level to load but the others are not, and also they can be placed in levels which did not originally have them.  
+
Level collision in Sonic Heroes is defined in big endian .cl files located in dvdroot/collisions in the PC version. These files are not RenderWare collision files and are the same between different versions of the game. s*.cl files contain normal level collision, s*_xx.cl files contain collision for death boundaries and s*_wt.cl files contain water boundaries. The s*.cl file is required for the level to load but the others are not, and also they can be placed in levels which did not originally have them.  
  
Format is only partly known.
+
The game uses a [https://en.wikipedia.org/wiki/Quadtree quadtree] based system to optimize collision detection: a square plane is drawn over a top-down 2D projection of the stage (thus ignoring the Y axis). This square is subdivided into 4 squares of the same size. Each square which has a collidable mesh inside of it will be again subdivided into 4 same-sized children. This is repeated usually 9 or 10 times for most main level models (and 2 or 3 for xx and wt), thus creating a maximum of 4^9 or 4^10 squares (the actual number is much smaller as most squares don't have anything in them). Each quadtree node will reference a small list of triangles. When inside that node's range, the player and objects' position will be checked for collision only against those triangles, thus optimizing the collision detection. Not using the quadtree will slow down game performance by a large amount. Each triangle has individual collision flags and a normal unit vector. The maximum number of vertices, triangles and quadtree nodes is 0xFFFF each.
  
 
== File Format ==
 
== File Format ==
Line 20: Line 20:
 
   
 
   
 
  // TRIANGLE LIST SECTION
 
  // TRIANGLE LIST SECTION
  // This section is a list of triangles which comes right after the header. Each entry is 0x04 bytes long, containing indicies to the triangles from the triangle section. The lists are referenced by the quadtree by offset to know which triangles are inside each node. Due to that, there is no pointer/offset to this section in the header.
+
  // This section is a list of triangles which comes right after the header, starting at offset 0x28. Each entry is a word (0x02 bytes) long, containing zero-based indicies referencing the triangle section. This list is referenced by the quadtree by offset to know which triangles are inside each node. Due to that, there is no pointer/offset to this section in the header (and the amount of entries can pass 0xFFFF).
 
   
 
   
 
  // QUADTREE SECTION
 
  // QUADTREE SECTION
Line 26: Line 26:
 
  uint16 // index
 
  uint16 // index
 
  uint16 // parent
 
  uint16 // parent
  uint16 // child (index of first child in the group of four)
+
  uint16 // child (index of first child in the group of four, 0 if no child)
  uint16 // right neighbour
+
  uint16 // right neighbour, 0 if edge of level
  uint16 // left neighbour
+
  uint16 // left neighbour, 0 if edge of level
  uint16 // bottom neighbour
+
  uint16 // bottom neighbour, 0 if edge of level
  uint16 // top neighbour
+
  uint16 // top neighbour, 0 if edge of level
 
  uint16 // number of triangles in node
 
  uint16 // number of triangles in node
 
  uint32 // offset to triangle list for this node (relative to start of file)
 
  uint32 // offset to triangle list for this node (relative to start of file)
  uint16 // positioning offset value #1 (left/right)
+
  uint16 // positioning offset value (left/right)
  uint16 // positioning offset value #2 (top/bottom)
+
  uint16 // positioning offset value (top/bottom)
 
  uint8 // depth level (parent's depth level+1)
 
  uint8 // depth level (parent's depth level+1)
 
  uint8 // null
 
  uint8 // null
Line 41: Line 41:
  
 
  // The nodes are laid out in groups of four; if a node has children, then it necessarily has four; the index in the parent's entry is the index of the first (top left) child. The order of the children is always top left, top right, bottom left, bottom right.
 
  // The nodes are laid out in groups of four; if a node has children, then it necessarily has four; the index in the parent's entry is the index of the first (top left) child. The order of the children is always top left, top right, bottom left, bottom right.
  // This is how positioning offset values work: all four nodes of the 4-sibling group take their values initially from their parent. Then, a factor of (0x2000/2^(depth level)) is added to the first value on the second and fourth nodes (which are the right ones), and the same factor is added to the second value on the third and fourth nodes (which are the bottom ones). Note that the first (top left) node keeps the same values from the parent.
+
  // This is how positioning offset values work: all four nodes of the 4-sibling group take both their values initially from their parent. Then, a factor of (0x2000/2^(depth level)) is added to the first value on the second and fourth nodes (which are the right ones), and the same factor is added to the second value on the third and fourth nodes (which are the bottom ones). Note that the first (top left) node keeps the same values from the parent.
  // The quadtree is laid out from a top-down view of the level, (right side being towards positive X and bottom towards positive Z). Y values are ignored (including the one on the header) as the tree is 2-dimensional.
+
  // Right side is towards positive X and bottom towards positive Z. Y values are ignored (including the one on the header) as the grid is 2-dimensional.
 
   
 
   
 
  // TRIANGLE SECTION
 
  // TRIANGLE SECTION
  // Triangle entry (0x20 bytes, repeats the amount of times set in the header):
+
  // Triangle entry (0x20 bytes):
  uint16 // vertex1 index
+
  uint16[3] // vertex index 1, 2, 3 (counterclockwise)
uint16 // vertex2 index
+
  uint16[3] // adjacent triangle index 1, 2, 3
uint16 // vertex3 index
+
  float32[3] // normal unit vector X, Y, Z (can be calculated by doing [https://en.wikipedia.org/wiki/Cross_product cross product] of vectors vertex(2-1) and vertex(3-1) and then dividing each value by the vector's norm)
  uint16 // adjacent triangle 1 index
+
  int8[8] // col flags
uint16 // adjacent triangle 2 index
 
  uint16 // adjacent triangle 3 index
 
float32 // unknown; always a float between -1 and 1
 
float32 // unknown; always a float between -1 and 1
 
float32 // unknown; always a float between -1 and 1
 
  int8[4] // col flags
 
int8[4] // col flags (2)
 
 
   
 
   
  // adjacent triangle 1: vertex1 of current triangle is vertex3 of adjacent; vertex2 of current triangle is vertex2 of adjacent
+
  // adjacent triangle 1: vertex1 of current triangle is vertex3 of adjacent; vertex2 of current triangle is vertex2 of adjacent (unsure)
  // adjacent triangle 2: vertex2 of current triangle is vertex1 of adjacent; vertex3 of current triangle is vertex3 of adjacent
+
  // adjacent triangle 2: vertex3 of current triangle is vertex1 of adjacent; vertex2 of current triangle is vertex2 of adjacent (unsure)
  // adjacent triangle 3: vertex1 of current triangle is vertex1 of adjacent; vertex3 of current triangle is vertex2 of adjacent
+
  // adjacent triangle 3: vertex1 of current triangle is vertex1 of adjacent; vertex3 of current triangle is vertex2 of adjacent (unsure)
 
  // adjacent triangle index is FF FF if it doesn't exist
 
  // adjacent triangle index is FF FF if it doesn't exist
 
   
 
   
 
  // VERTEX SECTION
 
  // VERTEX SECTION
  // Vertex entry (0x0C bytes, repeats the amount of times set in the header):
+
  // Vertex entry (0x0C bytes):
 
  float32[3] // X, Y, Z position
 
  float32[3] // X, Y, Z position
  

Revision as of 00:43, 20 June 2017

SCHG: Sonic Heroes
Main Article
Mechanic Editing

DOL Editing
EXE Editing
Music Pointers
Object Parameter Data
Relocatable Editing (PC)
File Offsets

Model Editing
Collision Format
Model Format
Level Editing

Camera Editing
Event Editing
ID list
Indirect Editing
Light Editing
Level List
Object Editing
Object Porting
Spline Editing
Texture Animation Editing
Visibility Editing

Particle Editing
Particle Editing
Sound Editing
Music List

Sound Editing
Voices

SCHG How-Tos

Custom Object Material Effect Tutorial
Level Editing Tutorial


Level collision in Sonic Heroes is defined in big endian .cl files located in dvdroot/collisions in the PC version. These files are not RenderWare collision files and are the same between different versions of the game. s*.cl files contain normal level collision, s*_xx.cl files contain collision for death boundaries and s*_wt.cl files contain water boundaries. The s*.cl file is required for the level to load but the others are not, and also they can be placed in levels which did not originally have them.

The game uses a quadtree based system to optimize collision detection: a square plane is drawn over a top-down 2D projection of the stage (thus ignoring the Y axis). This square is subdivided into 4 squares of the same size. Each square which has a collidable mesh inside of it will be again subdivided into 4 same-sized children. This is repeated usually 9 or 10 times for most main level models (and 2 or 3 for xx and wt), thus creating a maximum of 4^9 or 4^10 squares (the actual number is much smaller as most squares don't have anything in them). Each quadtree node will reference a small list of triangles. When inside that node's range, the player and objects' position will be checked for collision only against those triangles, thus optimizing the collision detection. Not using the quadtree will slow down game performance by a large amount. Each triangle has individual collision flags and a normal unit vector. The maximum number of vertices, triangles and quadtree nodes is 0xFFFF each.

File Format

// HEADER (0x28 bytes)
uint32 // total number of bytes in file
uint32 // quadtree section offset
uint32 // triangle section offset
uint32 // vertex section offset
float32[3] // X, Y, Z center of quadtree
float32 // size of quadtree
uint16 // unknown // 0x01 for xx/wt, 0x0C or Ox0D for stages
uint16 // number of triangles
uint16 // number of vertices
uint16 // number of quadtree nodes

// TRIANGLE LIST SECTION
// This section is a list of triangles which comes right after the header, starting at offset 0x28. Each entry is a word (0x02 bytes) long, containing zero-based indicies referencing the triangle section. This list is referenced by the quadtree by offset to know which triangles are inside each node. Due to that, there is no pointer/offset to this section in the header (and the amount of entries can pass 0xFFFF).

// QUADTREE SECTION
// This section is a list of quadtree nodes. Each entry is 0x20 bytes long and the amount of entries is set in the header.
uint16 // index
uint16 // parent
uint16 // child (index of first child in the group of four, 0 if no child)
uint16 // right neighbour, 0 if edge of level
uint16 // left neighbour, 0 if edge of level
uint16 // bottom neighbour, 0 if edge of level
uint16 // top neighbour, 0 if edge of level
uint16 // number of triangles in node
uint32 // offset to triangle list for this node (relative to start of file)
uint16 // positioning offset value (left/right)
uint16 // positioning offset value (top/bottom)
uint8 // depth level (parent's depth level+1)
uint8 // null
uint16 // null
uint32 // null
// The nodes are laid out in groups of four; if a node has children, then it necessarily has four; the index in the parent's entry is the index of the first (top left) child. The order of the children is always top left, top right, bottom left, bottom right.
// This is how positioning offset values work: all four nodes of the 4-sibling group take both their values initially from their parent. Then, a factor of (0x2000/2^(depth level)) is added to the first value on the second and fourth nodes (which are the right ones), and the same factor is added to the second value on the third and fourth nodes (which are the bottom ones). Note that the first (top left) node keeps the same values from the parent.
// Right side is towards positive X and bottom towards positive Z. Y values are ignored (including the one on the header) as the grid is 2-dimensional.

// TRIANGLE SECTION
// Triangle entry (0x20 bytes):
uint16[3] // vertex index 1, 2, 3 (counterclockwise)
uint16[3] // adjacent triangle index 1, 2, 3
float32[3] // normal unit vector X, Y, Z (can be calculated by doing cross product of vectors vertex(2-1) and vertex(3-1) and then dividing each value by the vector's norm)
int8[8] // col flags

// adjacent triangle 1: vertex1 of current triangle is vertex3 of adjacent; vertex2 of current triangle is vertex2 of adjacent (unsure)
// adjacent triangle 2: vertex3 of current triangle is vertex1 of adjacent; vertex2 of current triangle is vertex2 of adjacent (unsure)
// adjacent triangle 3: vertex1 of current triangle is vertex1 of adjacent; vertex3 of current triangle is vertex2 of adjacent (unsure)
// adjacent triangle index is FF FF if it doesn't exist

// VERTEX SECTION
// Vertex entry (0x0C bytes):
float32[3] // X, Y, Z position

Collision Flags

These are probably set at bit level, each byte with a different meaning, but here they are presented as 4 bytes. They are guesses and the list might be wrong and incomplete.

  • 00 00 00 00 - Floor (normal)
  • 00 00 00 01 - Floor (grass offroad)
  • 00 00 00 02 - Water boundary
  • 00 00 00 10 - Floor (sand)
  • 00 00 00 20 - Floor (grass road)
  • 00 00 00 80 - Floor (rock)
  • 00 00 01 00 - Wall
  • 00 00 01 80 - Wall (rock)
  • 00 00 04 00 - Floor (carpet staircase)
  • 00 00 80 00 - Wall (invisible barriers)
  • 00 01 00 00 - Death boundary
  • 00 04 00 80 - Wall (pinball table and bingo slide)
  • 00 08 00 00 - Wall
  • 40 00 00 00 - Bingo slide
  • 80 00 00 00 - Pinball table

Remember this is still a Sonic game, so these types of surfaces probably help the physics engine decide what to do, but of course you can walk on walls given you have enough speed. Same applies to vertical floors being the same as walls (all of Test Level's collision model is type 00 00 00 00).

Sonic Community Hacking Guide
General
SonED2 Manual | Subroutine Equivalency List
Game-Specific
Sonic the Hedgehog (16-bit) | Sonic the Hedgehog (8-bit) | Sonic CD (prototype 510) | Sonic CD | Sonic CD (PC) | Sonic CD (2011) | Sonic 2 (Simon Wai prototype) | Sonic 2 (16-bit) | Sonic 2 (Master System) | Sonic 3 | Sonic 3 & Knuckles | Chaotix | Sonic Jam | Sonic Jam 6 | Sonic Adventure | Sonic Adventure DX: Director's Cut | Sonic Adventure DX: PC | Sonic Adventure (2010) | Sonic Adventure 2 | Sonic Adventure 2: Battle | Sonic Adventure 2 (PC) | Sonic Heroes | Sonic Riders | Sonic the Hedgehog (2006) | Sonic & Sega All-Stars Racing | Sonic Unleashed (Xbox 360/PS3) | Sonic Colours | Sonic Generations | Sonic Forces
Technical information
Sonic Eraser | Sonic 2 (Nick Arcade prototype) | Sonic CD (prototype; 1992-12-04) | Dr. Robotnik's Mean Bean Machine | Sonic Triple Trouble | Tails Adventures | Sonic Crackers | Sonic 3D: Flickies' Island | Sonic & Knuckles Collection | Sonic R | Sonic Shuffle | Sonic Advance | Sonic Advance 3 | Sonic Battle | Shadow the Hedgehog | Sonic Rush | Sonic Classic Collection | Sonic Free Riders | Sonic Lost World
Legacy Guides
The Nemesis Hacking Guides The Esrael Hacking Guides
ROM: Sonic 1 | Sonic 2 | Sonic 2 Beta | Sonic 3

Savestate: Sonic 1 | Sonic 2 Beta/Final | Sonic 3

Sonic 1 (English / Portuguese) | Sonic 2 Beta (English / Portuguese) | Sonic 2 and Knuckles (English / Portuguese)
Move to Sega Retro
Number Systems (or scrap) | Assembly Hacking Guide | 68000 Instruction Set | 68000 ASM-to-Hex Code Reference | SMPS Music Hacking Guide | Mega Drive technical information