Portal 2

Portal 2

48 ratings
Custom model textures with model hexing
By anna
How to put a custom texture on a model that is already in the game. This works without having to decompile and recompile the model. You can basically just edit the mdl file in a text editor and replace the texture name (model hexing).

Want a custom skin on your cube, button or testchamber door?
This guide will show how to do that and also how to get the model from the game files, how to find its textures, how to export them for editing, how to convert the edited images to textures again, how to put your edited model back in the game and also how to pack it in your map file so you can publish it on the workshop.
   
Award
Favorite
Favorited
Unfavorite
What now, exactly?
Custom textures?
First things first: This guide is about putting custom textures on models. If you're looking for a guide on how to get custom textures in your map that you can put on walls and floors and the likes, then this is not it! Please refer to here or here or here or here and don't forget to pack your custom content into the bsp before publishing!

Okay, for everyone else still with us, here are some examples of what we can do:

The cool thing about the button, turret, etc. in this image here is that they do not just look pretty, they actually work. Meaning the turret will shoot you, the box will activate the button etc.*
We're going to do this "reskinning" by copying the actual model file and modifying it so it points to another (custom) texture file.
Adding a skin to an existing model is not possible in this way. We have to copy the model and modify it a bit so it uses our new texture.

* we have to do some vscripting to actually change the model, but that's all.

This guide is directed towards hammer users. This will not work if you're using the ingame (PeTI) editor or beemod!
Software needed
We're gonna need a few tools for this:
  • GCFScape[nemesis.thewavelength.net]
    This is for browsing the game files and extracting models and textures from them
  • VTFEdit[nemesis.thewavelength.net]
    For converting source engine texture files to normal images and vice versa.
  • mdltextureinfo[www.wunderboy.org] (scroll down a bit)
    Reads a model file and tells us which textures it's using
  • GIMP[www.gimp.org] or Photoshop or something similar
    to actually edit the texture or make your own
  • Notepad++[notepad-plus-plus.org] (and maybe a Hex Editor like HxD[mh-nexus.de])
    for editing the model file. You cannot do this in the standard editor because it does not save binary files correctly. Also, Notepad++ displays binary files better anyway, has a better replace dialog and it's the thing I'm using to explain what to do. The hex editor also helps when editing binary files
  • Portal 2 and the Portal 2 Authoring Tools
    obviously.
Overview
Here I'll provide a basic overview of the several steps we're going to do:
  1. Selecting your model and extracting it from the game's files
  2. Finding out which textures are used and extracting them as well
  3. Exporting textures to images so we can edit them
  4. Creating new textures from the edited images
  5. Modifying the actual model file with notepad so it uses a new name and the new textures
  6. Putting it all back into the game
  7. Getting the new custom model file ready for publising in a map on the workshop
Getting the files
Selecting your model
First, you have to select which model you want to modify.
Write down the path of the model you see in hammer.
For example, the path for the weighted storage cube model would be props/metal_box.mdl


Extracting your model
Now open GCFScape and select File > Open
Navigate to
<Steam Installation Directory>/steamapps/common/Portal 2/portal2
and then open pak01_dir.vpk all the way at the bottom.
Now you see a models folder among others. Open the models folder and then navigate to your model using the path you wrote down earlier.

(If you cannot find your model here, try opening
<Steam Installation Directory>/steamapps/common/Portal 2/portal2_dlc1/pak01_dir.vpk
or
<Steam Installation Directory>/steamapps/common/Portal 2/portal2_dlc2/pak01_dir.vpk
in GCFScape and see if it's in there)

You should see five files with the name of your model:

Select them all and drag them into a folder on your Desktop or wherever you want to extract them.

Don't close CGFScape yet, we're gonna need it again in a second.

Finding the materials
Now we want to know which textures are used by this model.
To do this, navigate to where your MDLTextureInfo.exe is and drag the file ending in .mdl of the 5 files you just extracted onto it.
A command line window opens and you should get an output like this:

From this we should now be able to piece together where the materials (not the textures, yet) for this model are located.
The entries in "TEXTURE FOLDER(S)" tell you in which folder the materials are and the "TEXTURE NAMES" entries are the actual names of the materials (pretty straight forward).

Depending on the model, there may be multiple paths used by the different textures and it won't tell you which of the textures uses which path. For example, here's the output of the floor button model:

Materials for models are generally found in <Game Folder>/materials/models/...
So here we can quickly conclude that the materials are in <Game Folder>/materials/models/props/. In the worst case you'll have to do some quick digging through the different paths listed to find the files.

Extracting the materials and textures
We may now go back to GCFScape and extract the materials. First, go back to the root folder by clicking on "root" atop the file tree on the left. Then navigate to materials and then to the respective paths used by the materials that we got from MDLTextureInfo. The materials are the files ending in .vmt and you want to extract those. Most of the time, there will be a file ending in .vtf with the same name as the material. This is most likely the actual texture used by this material, so extract it as well.
I say most likely because the texture (.vtf) may have a different name and path than the .vmt material file that uses it. To get all the right textures, open all the .vmt files you just extracted in Notepad++. You will find a line that begins with $basetexture. This is the actual path of the texture that is used by this material, relative to the <Game Folder>/materials/ folder.

Example:
For the floor button model, I get these materials (see example above):
/materials/models/props/portal_button_switch.vmt /materials/models/props/portal_button_blue.vmt /materials/models/props/portal_button_orange.vmt
When navigating to /materials/models/props in GCFScape, I find:

So portal_button_switch.vmt has no texture apparently? No. If we extract it and open it in Notepad++, we can see this line:
$basetexture "models\props\portal_button_blue"
This tells us that /materials/models/props/portal_button_blue.vtf is the actual texture used by this material. In our example here, we already extracted that anyway. If we hadn't, we could now go find and grab it in GCFScape.

When you got all the materials and textures, you can now close CGFScape.
Exporting textures
Now that we have the texture files, you can go through them and decide which of them you want to modify.
We now need to export these textures from .vtf files to a format like PNG we can open with an image editor.
To do this, open VTFEdit. Go to File > Open and browse to your extracted .vtf files. Open the one you want to export. Hit File > Export and then save the image somewhere. Under "Save as type", be sure to select PNG Files or TGA Files.
Never select JPEG or BMP, you will lose texture quality or the alpha channel of the texture, which is important!

You can now go ahead and do your modifications to the textures in any image editing software that supports transparency, like GIMP or Photoshop.

Important note regarding alpha channels
Most textures have some kind of additional information stored in the alpha (transparency) channel of the image (e.g. self illumination data that tells the texture where to glow. How the alpha channel is used is specified in the .vmt material file of the texture. You can read more about materials here and different shader parameters here).

So if you open a texture exported as PNG in GIMP it might look something like this:

If you want to properly edit the RGB channels, you need to separate the alpha channel first. In GIMP, you can do this by right clicking on the current layer in the "Layer" window, then click "Add Layer Mask", select "Transfer layer's alpha channel" and press "Add":

The alpha channel is now in a mask. You can then right click on the layer and choose "Disable Layer Mask" to show the full texture:

You can edit the mask as well if you want to and know what you're doing.

Warning: Do not select "Remove alpha channel"! It will override the RGB values of the texture you want by painting them on a white backdrop with the alpha mask applied. It will look like this and not like the texture you want:


When exporting from GIMP, be sure to reenable the layer mask. Then delete every layer that you do not want to export. Hiding them is not enough.* If you've got multiple layers, merge them into one first by right clicking on the layers and pressing "Merge visible layers".
THERE MUST BE ONLY ONE AND EXACTLY ONE LAYER BEFORE YOU CAN PROPERLY EXPORT YOUR IMAGE!
Then go to File > Export As to save your image. Select PNG as the file type by ending your filename with ".png" and hit "Export". In the following dialog box, make sure "Save color values from transparent pixels" is checked.

* The reason for this is that we want to save RGB color values even if they're completely transparent (i.e. the alpha channel of the pixel is 0). GIMP cannot determine a transparent pixels color if there is more than one layer present, even if it is hidden. After exporting, you can undo the deletion of the layers. Just don't save with the layers deleted ;)
Creating new textures
After you have made your custom texture image in your favourite image editor and exported it as PNG (and with the correct transparency settings (preserving color values for transparent pixels) if you have an alpha mask), it is time to create a custom .vtf texture file from your image.

Open VTFEdit again and go to File > Import and select your image. A dialog box with settings will pop up. Just press OK. You should now see your texture in VTFEdit. (If you have an alpha channel and you see completely blank/white/black spots where the alpha channel is 0, i.e. completely transparent, that means you must've done something wrong when exporting your PNG form GIMP. Make sure you closely follow the steps in the earlier section on "Important note regarding alpha channels")

Now you can go to File > Save and save your texture as a .vtf file. Don't worry too much about a name yet, we will get back to that.

Material files
Your texture needs a material file so the game (and your model) can use it. VTFEdit generates one for you by default next to your saved .vtf file. If it does not, make sure Options > Auto create VMT File is checked in VTFEdit before saving your .vtf texture.
Now depending on whether you want to keep the material settings that the material you exported had or if you want to create a new one from scratch, there's two courses of action here:

Option 1: New material
This is the option you choose if you don't know too much about vmt materials and shader parameters or if your image had some information in the alpha channel and you ditched it and just want to create a normal plain ol' simple texture.
The .vmt generated by VTFEdit is fine, but it's not using the correct shader. Open the .vmt that was generated for your texture in Notepad++. You'll see something like this:
"LightmappedGeneric" { "$basetexture" "path/to/your/texture/mytexture" }
Replace LightmappedGeneric by VertexLitGeneric and save the file. Be sure not to mess up any of the quotation marks.

Option 2: Copy original material
Choose this option if there are shader parameters on the material you'd like to keep or if your texture has some alpha channel information that you kept when editing
You'll want to delete the .vmt generated by VTFEdit and copy the original one you extracted for this texture. Rename it to something you like.

Continue reading here:
We now have texture files and material files. So far so good. Now, we still need to move those into the game directory, name them appropriately and edit the material file once more in the next section, but we're done with exporting/editing/importing textures.
Editing the model
Now this is the part we're all here for, eh?
Open the .mdl file you extracted in Notepad++ or HxD
You'll see a bunch of binary gibberish like this:


Make note of the file length in the bottom bar of the editor:

We'll check this again at the end to make sure we did not alter the file length (this almost certainly breaks binary file structures)

Changing the model name

Recall the model path from the beginning of the guide. You'll want to get that without any model/ or whatever in front and with .mdl at the end. Also make sure the directory separating slashes are forward slashes (/) and not backward (\)!
So for example the weighted storage cube path would be:
props/metal_box.mdl
Or the floor button:
props/portal_button.mdl
It's this string you see here near the start of the binary stuff:


If you've got that string, figure out its length and then choose a name for your custom model that is the same length (number of characters) as that string, but not the same (since we do not want to replace the model). Chose a name that is not used by another model and also one that is a file path because you'll have to put your model there in the next section ("Adding your new model")!
For example:


Now press Ctrl + H in Notepad++ to open the Replace dialog (Search > Replace) and put the original name into "Replace what" and the new name into "Replace with". Make sure there are no spaces at the beginning or the end. Then press "Replace All".

(If you're using HxD, you can just write over the string in the ASCII Text section on the right. Make sure to replace all occurences, there are usually two)

Changing materials
Now we want to edit which materials are used by the model so we can use our own custom materials and textures we made earlier.
Recall the list of material names given by MDLTextureInfo.exe earlier. Scroll to the bottom of the .mdl file in your editor and there they all are, separated by a lovely character.
Now, once again, for all the materials you do want to change, think of a new name/path with the same length as the strings already present inside the .mdl file, between the characters.
These paths are relative to the texture paths given by MDLTextureInfo.exe earlier and do not have .vmt at the end! Chose paths where you can actually put the textures, because that's what we will do in the next section ("Adding your new model").
Do not give new names/paths to materials you do not intend to change. If you leave them, they'll just use the same material as the original model.

So, for example for the floor button, the mdl file looks like this at the end:

and the material string thus are:
models/props/portal_button_switch models/props/portal_button_blue portal_button_orange
and you need to create new name strings with the same length as those.
For the purple floor button in the thumbnail for this guide my strings for example were:
models/props/portal_button_purple models/props/portal_button_purp portal_button_purple

Now go ahead and replace the strings in the mdl file. I would adivse against using the replace dialog because strings can appear more than once and you might replace something you did not want to. Just write your strings in where the current ones are and make sure they're the same length and you're not introducing any spaces or removing any s.
(If you're using HxD, you can actually also choose shorter strings and then pad the rest of the bytes with zero bytes because the strings are null-terminated. If you do not know what that means, stick to the notepad method)

After all that, you can save the mdl.
Now make sure that the file length seen in the bottom bar of Notepad++ is still the same as in the beginning. If it's not, you messed something up and the file is probably broken, so try again!
Adding your new model
Now that we have our new custom .mdl file, we can add it to the game! Open
<Steam Installation Directory>/steamapps/common/Portal 2/portal2
and navigate to the models folder (or create it if it does not exist).
Now inside the models folder, navigate to or create the path you chose for your custom model in the last section.
For example, for the chosen path "mymdl/custombox.mdl" I would create a mymdl folder in the models folder and then copy my custom model in there and rename it to custombox.mdl.
You then also have to copy the other 4 files you originally extracted along with the .mdl file. While they do not need to be edited, they need to be copied to the same folder as your new custom model and need to have the same new name (except file extension):


Adding the materials and textures
Copy all the new .vmt files we prepared in the "Creating new textures: Material Files" section to the location you chose for them in the last section when replacing the materials strings.
All the materials strings are relative to:
<Steam Installation Directory>/steamapps/common/Portal 2/portal2/materials/
They need to be there because we specified in the model that they would be there.
Once you copied them over, you can also copy over your .vtf textures. It would be best to place them just next to (i.e. in the same folder) as their corresponding .vmt file.
Now we know the definitive location for all the .vtf files.
This means it's time to reopen all the .vmt files (the ones we just copied over inside the game directory) and to adjust the paths of the textures.
For each .vmt, locate the .vtf you want to point to and get the path relative to the materials folder. Then remove the .vtf at the end. This is your texture path
Replace the old path in the .vmt after the $basetexture parameter.

Example:
Let's say I specified a material "models/props/portal_button_purple" inside my custom model.
I would then copy the .vmt file for this material to
<Steam Installation Directory>/steamapps/common/Portal 2/portal2/materials/models/props/
and name it portal_button_purple.vmt
Then, I would copy the texture for this material, which I'm going to name floor_button_purple.vtf, to the same location. (Normally you would choose the same name as the vmt, but it is not mandatory and I'm choosing a different name to show how it affects the value for the $basetexture parameter, which could otherwise be confused with the vmt path)
So my texture is now at
<Steam Installation Directory>/steamapps/common/Portal 2/portal2/materials/models/props/floor_button_purple.vtf
This means, the path relative to the materials folder and without the extension is:
models/props/floor_button_purple
So this will be what I put after the $basetexture parameter, and the .vmt file now looks like this:


That's it!
You can now try out if adding your model worked.
Open the Authoring Tools and then open Model Viewer.
Go to File > Open and select your custom model.

Troubleshooting
  • If you get an error saying "Error loading model", you probably did not replace the model name in the file correctly.
  • If Model Viewer crashes, your file length may be off. Be sure not to change the file length when replacing strings in the mdl file!
  • If you get a black and purple checkerboard pattern on your model instead of your texture, verify that the .vmt is in the correct place and also that the .vtf files are at the location specified in the .vmt files!
Using the model in your map
All models can be used normally as prop_static or prop_dynamic or prop_physics, as you would normally use a model.
However, some of Portal 2's test elements use special entities, for example the weighted storage cube is prop_weighted_cube or the turret is npc_portal_turret_floor.
On these entities, it is not possible to change the model in hammer.
It is however possible to change the model using VScript functions.

Create a script called modelchanger.nut in
<Steam Installation Directory>/steamapps/common/Portal 2/portal2/scripts/vscripts/
with the following content:
function ChangeModel() { Entities.FindByName(null,"modelname").SetModel("path/to/my/model.mdl") }
Replace "modelname" with the name of your model entity and "path/to/my/model.mdl" with the path to the custom model you want to set it to!
Then add a logic_script and a logic_auto to your level.
Set the logic_script's "Entity Scripts" value to "modelchanger.nut" and give it a name like modelchangerscript
Then add this output to the logic_auto:
OnMapSpawn > modelchangerscript > RunScriptCode > ChangeModel()

Of course, you would want to make a more advanced version of this that automatically sets the model when entities get created, for example when respawning cubes, but for the sake of brevity I'm not going to demonstrate that here. This is just the basic idea of how to change the model on those special entities.
Publishing
Make sure to pack any custom content in your map before publishing.
This includes the custom model files (all 5 per model), its materials and textures and also the custom vscript if you're using one.
How to pack custom content has been explained numerous times by numerous people, so I'll just leave a link here to VIDE[www.riintouge.com] or PakRat
and a tutorial for VIDE[www.tophattwaffle.com]
(video tutorial for PakRat)

Thanks for reading! :)
14 Comments
Xilivir Apr 27, 2021 @ 2:36am 
i have a question: if i created retextured door,faith plate etc in vtf and in the same path,should i follow the same instructions?
Xilivir Apr 26, 2021 @ 9:14am 
but its hard...
Xilivir Apr 26, 2021 @ 9:13am 
блин учите Английский,не опозоретесь!!! Dude thank u very much!!!!!
:steamthumbsup:
Portal Timurker Oct 11, 2019 @ 12:54pm 
НА | РУ | СКОМ!!!!!😠😡😠😡😠😡👿
anna  [author] Oct 8, 2019 @ 8:57am 
i don't know, i don't speak russian LOL
Portal Timurker Oct 8, 2019 @ 6:34am 
А как ваш комментарий будет на русском языке?
anna  [author] Sep 30, 2019 @ 11:38am 
@Timurker I'm sorry, what?
Portal Timurker Sep 30, 2019 @ 3:28am 
а где про BLAPPERTURE MESA(У?)
maza Aug 25, 2019 @ 1:04am 
its toooooooooooooooooo long
jwejwefwfh Aug 24, 2019 @ 8:46am 
+ :p2orange: