The next generation of RAGE games, including GTA5 and RDR3, use an advanced audio occlusion system for interiors to accurately simulate how audio would filter and attenuate in the real world.
This system is driven by Occlusion Interior Metadata files, internally known as naOcclusionInteriorMetadata
, which are a type of tuning file (PSO #mt).
naOcclusionInteriorMetadata1
Field | Type | Description |
---|---|---|
PortalInfoList | array of naOcclusionPortalInfoMetadata2 | Portal metadata entries |
PathNodeList | array of naOcclusionPathNodeMetadata3 | Path node metadata entries |
naOcclusionPortalInfoMetadata
Field | Type | Description |
---|---|---|
InteriorProxyHash | uint324 | Interior instance proxy hash5 |
PortalIdx | int32 | Portal index6 |
RoomIdx | int32 | Room index7 |
DestInteriorHash | uint324 | Destination interior instance proxy hash5; otherwise same as InteriorProxyHash |
DestRoomIdx | int32 | Destination room index |
PortalEntityList | array of naOcclusionPortalEntityMetadata8 | Attached portal entity metadata entries |
naOcclusionPortalEntityMetadata
Field | Type | Description |
---|---|---|
LinkType | uint32 | Link type for the attached portal entity; 1 if portal leads to the same interior, 2 if the portal leads to a different interior |
MaxOcclusion | float32 | Occlusion influence of attached entity; the higher the value, the stronger the occlusion |
EntityModelHashkey | uint32 | Hash string of the attached entity |
IsDoor | bool | True if the attached entity is a door, false otherwise |
IsGlass | bool | True if the attached entity is a window or glass, false otherwise |
naOcclusionPathNodeMetadata
Field | Type | Description |
---|---|---|
Key | uint324 | Path node key9 |
PathNodeChildList | array of naOcclusionPathNodeChildMetadata10 | Path node child metadata entries |
naOcclusionPathNodeChildMetadata
Field | Type | Description |
---|---|---|
PathNodeKey | uint324 | Path node key9 |
PortalInfoIdx | int32 | Index of portal info entry in PortalInfoList |
Notes
1 The filename of these #mt’s is the unsigned proxy hash.
2 Array is sorted by ascending RoomIdx, and then further sorted by PortalIdx.
3 Array is sorted by ‘path type’, then by ascending Key value.
4 Confirmed to be uint32. Although CodeWalker parses these as int32s.
5 Proxy hash is generated as such:
// CMloInstanceDef::CEntityDef::rage__fwEntityDef.position
vec3 mloPosition;
// CMloInstanceDef::CEntityDef::rage__fwEntityDef.archetypeName
int32 mloName;
uint32 proxyHash = ((mloName) ^ (mloPosition.X * 100) ^ (mloPosition.Y * 100) ^ (mloPosition.Z * 100)) & 0xFFFFFFFF;
6 This is not the same index as the array of CMloPortalDef’s in CMloInstanceDef’s. Instead, a special list is generated that includes two entries per CMloPortalDef’s; one for each portal face. The PortalIdx is the local index of the portal face belonging to the RoomIdx in question. A detailed example is included below.
v_trevors
limbo[0]
0->6 [0][0] // RoomIdx -> DestRoomIdx [PortalIdx][CMloPortalDef]
0->4 [1][1]
0->4 [2][2]
0->4 [3][3]
0->1 [4][11]
0->7 [5][12]
rm_bedroom01[1]
1->5 [0][4]
1->0 [1][11]
rm_bedroom02[2]
2->5 [0][5]
rm_Bathroom[3]
3->5 [0][6]
rm_Lounge[4]
4->0 [0][1]
4->0 [1][2]
4->0 [2][3]
4->5 [3][7]
4->7 [4][9]
4->7 [5][10]
rm_hallway[5]
5->1 [0][4]
5->2 [1][5]
5->3 [2][6]
5->4 [3][7]
5->6 [4][8]
rm_frontDoor[6]
6->0 [0][0]
6->5 [1][8]
rm_Kitchen[7]
7->4 [0][9]
7->4 [1][10]
7->0 [2][12]
7 This is the CMloRoomDef index as it would appear in a CMloInstanceDef.
8 Likely sorted by EntityModelHashkey. Citation needed.
9 Path Node Key is the difference between two room keys plus 1-5 (1-5 likely represents audio channels).
// Room Key formula
uint32 roomKey = (room.name == "limbo") ? (uint32)(jooat("outside")) : (uint32)(proxyHash ^ jooat(room.name));
// Path Node Key formula
uint32 pathNodeKey = (roomA == roomB) ? 0 : (roomA.key - roomB.key) + (uint32)pathType; // pathType is an int 1-5, likely an audio channel