Skip to content

Instantly share code, notes, and snippets.

@windwakr
Last active August 29, 2024 00:53
Show Gist options
  • Save windwakr/c1b2a455bce93053117f765277ab63a9 to your computer and use it in GitHub Desktop.
Save windwakr/c1b2a455bce93053117f765277ab63a9 to your computer and use it in GitHub Desktop.
Runescape 3 RS3 NXT 3D model format
Models in the cache have an lzma wrapper
BIG ENDIAN
1 byte, header 0x03
1 int, compressed size?
1 int, decompressed size?
compressed data
The model data itself
LITTLE ENDIAN
1 byte, header always 0x02?
2 bytes, unknown
1 short, segmentCnt
1 byte, billboard?
1 byte, particle1?
1 bytes, particle2?
segmentCnt TIMES
1 int, flags
0b0001 hasFaceColors
0b0010 hasFaceAlphas (?)
0b0100 unk1
0b1000 hasVertexSkins (?)
1 byte, unknown
1 short, materialIdx
1 short, faceCnt
if hasFaceColors
faceCnt shorts, face colors
if hasFaceAlphas
faceCnt bytes, face alphas?
if unk1
faceCnt shorts, unknown
1 byte, indexCnt (can be up to 5, I think)
indexCnt TIMES
1 short, length
length shorts, index (LODs?)
1 short, vertCnt
vertCnt TIMES
signed short, vertex X
signed short, vertex Y
signed short, vertex Z
vertCnt TIMES
signed byte, normal X
signed byte, normal Y
signed byte, normal Z
vertCnt TIMES [1]
signed byte, tangent X
signed byte, tangent Y
signed byte, tangent Z
signed byte, bitangent sign
vertCnt TIMES
float16BE, U
float16BE, V
if hasVertexSkins
vertCnt shorts, skinning related? [2]
if billboard
(TODO)
if particle1
(TODO)
if particle2
(TODO)
-----
Faces are built using the first index.
How do face colors get selected for LODs beyond the first?
Models are horizontally flipped?
Textures need to have the repeating edges cropped out for UVs to fit properly?
materialIdx is which file to read in Index 26 Archive 0.
They specify which diffuse/normal/whatever textures to use, etc. and other material settings.
[1] I've not actually tested that these bytes are tangent vectors, but they seem to be. The fourth one is always -128 or 127.
[2] From what I gather, these assign a vertex to a group.
There are keyframes that tell the groups how to move/rotate stored elsewhere. Please correct me if I'm wrong about this.
[WIP] Format of the files in Index 26, Archive 0
BIG ENDIAN
1 byte, materialType (old/new?)
if materialType == 0
1 byte, texture size?[1]
1 byte, unknown
1 int, flags
if (flags & 0x01) or (flags & 0x10)
1 int, texture id?
if (flags & 0x08) or (flags & 0x02)
1 int, unknown
1 byte, unknown &7 and >>3&7
1 int, moreflags
if (moreflags & 0x40000)
1 int, unknown
if (moreflags & 0x80000)
1 int, unknown
1 float?, unknown 1.0/value
1 float?, unknown 1.0/value
2 ints, unknown
if (moreflags & 0x10)
2 ints, unknown
if (flags & 0x02)
1 int, unknown
2 bytes, unknown
1 byte, unk1
if (unk1 == 1)
1 byte, unknown
if (moreflags & 0x800)
3 ints, unknown
1 byte, unk2
if (unk2 & 0x01)
1 signed short, unknown value * 0.000060560167
if (unk2 & 0x02)
1 signed short, unknown value * 0.000060560167
1 byte, unk3
if (unk3 == 0x01)
2 bytes, unknown
1 int, unknown
7 bytes, unknown
1 short, unknown
else
1 int, flags
if (flags & 0x20)
1 byte, texture size?[1]
1 int, texture id?
if (flags & 0x40)
1 byte, texture size?[1]
1 int, texture id?
if (flags & 0x80)
1 byte, texture size?[1]
1 int, texture id?
if (flags & 0x40000)
1 int, unknown
if (flags & 0x80000)
1 int, unknown
1 float?, unknown 1.0/value
1 float?, unknown 1.0/value
2 ints, unknown
if (flags & 0x1000)
1 int, unknown
if (flags & 0x2000)
1 int, unknown
if (flags & 0x4000)
1 int, unknown
if (flags & 0x40)
1 int, unknown
if (flags & 0x8000)
1 int, unknown
if (flags & 0x800)
3 ints, unknown
if (flags & 0x10000)
1 int, unknown
if (flags & 0x20000)
1 int, unknown
if (flags & 0x100)
1 signed short, unknown value * 0.000060560167
if (flags & 0x200)
1 signed short, unknown value * 0.000060560167
1 byte, unknown &7 and >>3&7
2 bytes, unknown
1 bytes, unk1
if (unk1 == 1)
1 byte, unknown
1 short, unknown
1 byte, unknown
-----
[1] some var set to 64,128,256,512,1024 depending on the value read
mat type 1
second texture: R channel = emission, G = normal G, B = normal B, Alpha = normal R
third texture: R channel = metal, G = roughness, B = ?
@windwakr
Copy link
Author

windwakr commented Feb 5, 2021

Raksha with textures. Two models, one is just the spikes.
Untitled2

Are the LODs even used in game?
LOD

@windwakr
Copy link
Author

Still trying to figure out the material type 1 setup. One of the textures has normal map + emission map, the other has metalness + roughness + ??.
Untitled

@windwakr
Copy link
Author

windwakr commented Apr 4, 2022

Some recent update added new flags for model segments. Haven't had a chance to check what the game code is doing, but flags & 32 seems to indicate an int and 3*that bytes at the end of a segment. Don't really care to look into it further than that, tbh. Not really interested in this anymore.

@windwakr
Copy link
Author

This is very outdated. If you're looking for info on RS3 model/cache formats then see Skillbert's excellent tool here
https://github.com/skillbert/rsmv

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment