Skip to content

Textures in the Mass Effect Trilogy

Mgamerz edited this page Dec 23, 2020 · 12 revisions

Textures in the Mass Effect Trilogy, and Unreal Engine 3 in general, are pretty tricky. They are one of two types of objects that heavily depend on file offsets to work properly, in that, they reference another file at an exact offset.

Mass Effect

Textures in Mass Effect are a real nightmare, as the externally stored textures are stored in UPK package files. As UPK package files often can change their file offsets (for example, adding an export will add an entry to the export table - which shifts all data after the table), it is extremely easy to break all of the inbound references. If you've tried to save packages in ME3Explorer and are greeted with a message saying you cannot save this package because of texture references, this is exactly why, because that file has known inbound references. The only way to safely update textures in these files is by global replacement, with a tool like Mass Effect Modder.

In ME1 there is a concept of Master and Slave textures. Slave textures have externally referenced mips (extZLib, extUnc) on the higher values. The package name can be determined by traversing up the full path of the object and using the top level package as the package name to search for.

In the above image, the top texture is the slave texture, and the bottom texture is the master package file's version. You can see the slave version has the external mips defined as extLZO, where as the master one has them as pccLZO. The offsets are into the package file itself, rather than into the export. These files are (for some reason) loaded and parsed as package files, so they must behave and look like normal package files.

If a slave texture has multiple package export parents, such as BIOT_STA20_Presidium.Eyeballs.Eyes_Diff (Eyes_Diff is the texture), In BIOT_STA20_Presidium will be a package export named Eyeballs, with the master texture residing within it. Otherwise, it will directly be in the root.

In ME3Explorer 5.1 there will be features that can update your mod's texture pointers that are going into a master texture package that you build. Due to the high levels of complexity for ME1 textures, great care must be taken to avoid breaking user's games and other modding tools, such as Mass Effect Modder. There are still many unknowns with regards to ME1 textures.

ME1 has many additional fun tricks. A few textures have multiple masters with the same CRC, which makes global replacement difficult. Some define a master but never actually use it. It's a real big ugly mess that is painful to support.

Mass Effect 2/3

Textures in Mass Effect 2/3 are much easier to work with than Mass Effect, in that the external texture data is stored in a Texture File Cache, or TFC. TFC files begin with 16 bytes representing their GUID, and are followed directly by headerless texture data concatenated one after the other.

These textures are referenced by data offsets in the external mips of a texture (storage types of extUnc, extZlib, extLZO), along with the filename and guid as properties of the texture. Only mips higher than 6 are stored externally, all lower ones are stored locally in the package. Mips above the 6th one, if stored locally, must be in an export that contains the NeverStream flag, with it's value set to true, otherwise the package will crash the game when LODs are raised and the file is loaded. You will see an I/O failure on the package file in ME3Logger output if this condition occurs.

Empty Mips

You may see the top mips of a texture stored as 'empty', and have no data. When the games were compiled, the source art sizes were often larger than the ones that could be used by the default Texture Level of Detail (LOD) settings. In ME2 and ME3 there are no graphical options, however you can think of LODs as ME1's texture quality settings - lower LODs = lower resolution textures.

When the game was compiled, any textures above the maximum vanilla LODs were replaced with empty stubs. In a vanilla setup, this causes no problems as those mips are never used. However if LODs are raised, these empty mips are attempted to be used, which are invalid. In ME2/3 this can occasionally crash the game, but most times appears to be ignored. In ME1 loading any empty 'unused' mip will cause the game to assert a crash.

Empty mip ME1 In the above image, you can see the assertion message for ME1. The filename not found strings are because there is not .pdb symbols file for the game (as it's a release build), so there is no referenced filename available.

Problems with offsets

Because of these offset systems, it is very easy to break textures. A broken texture will appear 100% black in game, and is caused by the referenced offset not pointing to the start of texture data - each texture starts with a texture magic number, and if that magic number is not correct, the game completely ignores the texture data and just fills in blanks.

For this reason, brand new Mass Effect (1) textures are extremely difficult to implement, as they are stored in packages, rather than TFCs. A TFC can be updated by simply appending new data to it and pointing the offset at the new position, but since ME1 stores them in other package files, that's not an option. When the package is saved, the offsets can very easily change, which will break all incoming references.

Clone this wiki locally