跳到主内容

文件夹转 YTD

把装满 PNG 的文件夹变成 GTA V 流送的贴图字典。一个文件夹就是一个 .ytd:文件夹名就是字典名,每张图片的文件名就是里面的贴图名,而这正是模型要找的名字。选择压缩格式、尺寸和 mipmap,每张贴图都会告诉你这个选择会带来什么,然后下载 .ytd 文件,或者下载一个带 stream 文件夹的现成资源。不用装转换器,也不会上传任何东西。

工具下面的说明目前是英文的。

配置与代码贴图, YTD, 批量, 下载查看文档

What a .ytd actually is

A .ytd is a texture dictionary: a named bag of textures, each with its own name, size, compression and mip chain. The game never looks any of that up by position. It looks it up by the joaat hash of a name, and there are two names in play:

  • The dictionary name is the file name without the extension. A .ytyp archetype'stextureDictionary field holds the hash of it, and RequestStreamedTextureDict takes it as a string.
  • A texture name is what a model's shader asks for. A drawable stores the name of the texture it wants, not a slot number.

That second one is the whole reason this page makes you look at the names. We checked it against the real game: of 2,629 stock .ydr models that sit next to a .ytd of the same name, 2,029 of the texture references resolve inside that dictionary by exact name, and the rest point at shared dictionaries like env_smooth_concrete2. Get a name wrong and that material draws untextured. There is no fallback.

How to use it

  1. Drop your folders. One folder becomes one .ytd. Subfolders each become their own dictionary, so you can drop a whole pack at once.
  2. Check the names. The folder name becomes the file name and each image name becomes a texture name. Both are lowercased and anything that is not a letter, number, underscore or dash becomes an underscore, because that is what survives a joaat lookup cleanly.
  3. Pick the compression. Auto gives DXT5 to anything with alpha and DXT1 to everything else.
  4. Build and download. You get a zip: the bare .ytd files, or a resource with anfxmanifest.lua and a stream/ folder.

The choices that can break your model

  • A renamed texture. If the model was asking for mywall_01 and the file is nowmywall01, the material goes untextured. The page tells you when it renames something.
  • Two textures with the same name in one dictionary. They hash to the same value, so only one can exist. This is refused, not silently resolved.
  • DXT1 on soft alpha. DXT1 carries one bit of alpha: a pixel is solid or gone, never half. Glass, shadows and soft edges need DXT5.
  • Non power of two sizes. They work, but only with a single mip level, so they sparkle at a distance. See below.

Why mipmaps stop at 4 px, and why sizes should be powers of two

A .ytd does not store a byte length per mip level. It stores one stride and a level count, and the reader takes each level as a quarter of the one before it. That quarter only lands on a real block count while both sides are powers of two, and it stops making sense once a side is under 4 pixels, because a block compressed level can never be smaller than one 4 x 4 block.

The game agrees with itself about this. In 2,000 stock dictionaries (6,921 textures) we read out of a real game install: 95.1% carry exactly the chain that halves down to 4 px, 5.7% carry a single level, nothing carries a chain down to 1 px, and of the 46 textures that are not a power of two, not one has a second mip level. So this page resizes to the nearest power of two by default, and when you tell it to keep an odd size it writes one level and says so.

Which compression to pick

Out of those same 6,921 stock textures:

  • DXT1 (BC1), 82%. Half a byte per pixel, RGB plus one bit of alpha. This is the default for almost everything, including normal maps: 1,208 of the 1,231 textures marked NORMAL in that sample are DXT1.
  • DXT5 (BC3), 16%. One byte per pixel, full alpha. Use it whenever alpha fades rather than switches.
  • ATI1 (BC4) and ATI2 (BC5) are there for one and two channel masks. The game uses them rarely.
  • A8R8G8B8 is uncompressed, four bytes per pixel, eight times DXT1. Worth it only where block artefacts really show.

Nothing in the base game we sampled is larger than 2048 on a side, which is why that is the default cap.

Getting it into the game

A .ytd in a resource's stream/ folder is handed to the streamer on its own. It needsno files entry and no data_file line. The manifest in the download is a name, a description and nothing else.

Streamed assets are read once when the server starts, so restart myresource will not pick up a new texture dictionary. Restart the whole server, and clear the server cache folder plus the client cache if the old one is still showing.

A dictionary on its own does nothing until something asks for it: a model through its archetype, or your own code through RequestStreamedTextureDict.

What this page will not do

  • It does not write BC7. Our reader understands it and the game ships a handful, but nothing here encodes it, so it is not offered.
  • It does not open .ytd files. To look inside one, resize what is already there or shrink a whole stream folder, use the YTD Optimizer or the Texture Editor.
  • It does not guess what your model wants. It cannot: the names live in the model, not in the images.

Everything is read, resized, compressed and written in your own browser by the same texture code behind the Texture Editor, the YTD Optimizer and the Map Tile Builder. Your images never leave the tab.