World & rooms

Room textures

The wall, floor, bathroom and ceiling textures a generated room rolls from, and how a mod adds its own.

A generated room keeps its kit's geometry and swaps the textures on its surfaces: plaster or wallpaper on the walls, wood on the floor, tiles in wet rooms (toilets, bathrooms), white plaster on the ceiling. Which textures a room may roll is mod data: Rooms/Textures/textures.ulset in any mod.

The list file

json{
  "wall": ["AmbientCG/Plaster001", "AmbientCG/Wallpaper001A"],
  "floor": ["PolyHaven/herringbone_parquet", "PolyHaven/laminate_floor_02"],
  "bath_floor": ["AmbientCG/Tiles002", "AmbientCG/Tiles071"],
  "bath_wall": ["AmbientCG/Tiles008", "AmbientCG/Tiles030"],
  "ceiling": ["AmbientCG/Plaster002"],
  "wall_tints": [[1.0, 0.98, 0.94], [0.80, 0.90, 0.80]],
  "floor_tints": [[1.0, 1.0, 1.0], [1.0, 0.92, 0.78]]
}
Field Meaning
wall Dry-room walls (plaster, wallpaper). Rolled per venue, then tinted.
floor Dry-room floors (wood, laminate). Never used in a wet room.
bath_floor Wet-room floors.
bath_wall Wet-room walls; half the wet rooms take one of these, the other half a wall texture with a tint.
ceiling Every generated room's ceiling.
wall_tints, floor_tints [r, g, b] multiplied onto wall / floor textures. Keep them near white: a plaster at ~215/255 times 0.8 already reads as a coloured wall. Tiles are never tinted.
remove { "floor": ["PolyHaven/old_wood_floor"] }: drops ids an earlier mod listed.
replace true: the lists this file names start empty instead of adding to the earlier ones.

Every enabled mod's file is read in load order: lists add up (an id already listed is not added twice), remove and replace act on what the mods before yours listed. A list nobody fills leaves that surface as the kit made it.

The same ids work in a look profile (floor_texture, wall_texture, see Looks) and are what the room editor offers the player. A save stores the id, so renaming a folder breaks the rooms players painted with it.

The texture folder

An id is <Source>/<Name>, a folder beside the list file:

textRooms/Textures/
  textures.ulset
  MyTiles/
    green_zellige/
      green_zellige_diffuse.dds   colour, BC1 (BC3 if it has alpha), with mips
      green_zellige_nor_gl.dds    normal map, BC5 (or BC3/BC1), OpenGL convention (green up), with mips
      green_zellige_rough.jpg     roughness, grey, 512 is plenty
      size.txt                    "0.6 0.6": metres covered by one repeat of the texture
  • When two mods ship the same id, the last one in load order wins: a mod can replace AmbientCG/Plaster002 without touching the list.
  • size.txt is what makes a 10 cm tile look 10 cm on any wall; without it the texture is stretched over 2 m.
  • A .jpg/.png in place of a .dds also loads, but decoded to 4 bytes per pixel with no mips: a 2048 colour map then costs 16 MB of graphics memory instead of 2.7 MB. The game targets 8 GB cards; ship .dds.
  • The roughness stays a plain image on purpose: the game raises it to a floor that depends on the surface (floors 0.28, walls 0.55, ceilings 0.8) so a glossy source does not turn into a mirror.

Making the files

From a folder of <name>_diffuse.jpg, <name>_nor_gl.jpg, <name>_rough.jpg (the Poly Haven and ambientCG layouts), Tools/RoomKitExport/ship_room_textures.py in the game repository writes all of the above for every id the mods list. Any tool that writes legacy-header or DX10 DDS works too: texconv -f BC1_UNORM -m 0 for the colour, texconv -f BC5_UNORM -m 0 for the normal map. 1024 pixels is enough for anything that repeats every metre or less; use 2048 only for floors whose texture covers 2.5 m or more and is seen up close.