Controlling animated textures in Hammer

Blinx

L69: Deviant Member
Mar 14, 2016
69
51
In this guide, I'm going to show you how you can manipulate animated textures in Hammer itself, such as making them start and stop, making them jump to a specific frame, and altering their frame rate.

1 - Preparing the VMT file

VMT files need to have a specific Proxy attached to them so that we can manipulate them in Hammer, this is called ToggleTexture, and it has some parameters we need to assign it, these are: toggleTextureVar, toggleTextureFrameVar and toggleShouldWrap.

toggleTextureVar is the texture we are going to be manipulating or "toggling", in almost all cases this is going to be the base texture that the VMT is assigned, so this key and value will look like:

Code:
"toggleTextureVar"    "$basetexture"

toggleTextureFrameVar does something but I'm not totally sure what, however it needs to be assigned the value "$frame", so this key and value will look like:

Code:
"toggleTextureFrameVar"    "$frame"

toggleShouldWrap is probably the only value that you'll change based on what you're hoping to accomplish, this is a 1/0 value that decides whether the texture should be allowed to wrap over to the beginning when it reaches the end via the input IncrementTextureIndex (which I'll explain later) in Hammer. This being 0 does not mean we can't send a texture back to the beginning if it reaches the end, it only means it can't be done via a certain Input. The key and value (if we're setting it to 1) will look like:

Code:
"toggleShouldWrap"    "1"

So your full material file will look something like this:

Code:
"LightmappedGeneric"
{
    "$basetexture" "custommats/billwurtz/shavingmypiano_full"
    "%keywords" "wurtz"

    "Proxies"
    {
        "ToggleTexture"
        {
            "toggleTextureVar"    "$basetexture"
            "toggleTextureFrameNumVar"        "$frame"
            "toggleShouldWrap"    "1"
        }
    }
}

2 - Setting up the Hammer logic

With the VMT set-up, we can now start playing with it in Hammer. Your texture must be applied to a brush-based entity, so that it can be targeted. The core point entity that allows us to manipulate textures is called env_texturetoggle. For this tutorial, I am going to be creating a func_brush with the material from earlier applied to it, make it start from the beginning of the animation, give it a framerate of 10, and then make it stop when it reaches the end.

So firstly, we need to create the func_brush, the only thing this needs defined is it's name, so it can be targeted. Let's just call it brush_example.

Next, we need to create the point_entity env_texturetoggle. This has only 2 Key-Values, it's name and Target Brush(es). We need to give it some name so we can target it later. Let's call it tt_example. The Target Brush(es), as you can imagine, is/are the brush-entity(s) that have a suitable VMT applied to it/them, so in our case it's brush_example.

Next, we need to create a logic_relay, so we can send inputs to the env_texturetoggle. It needs to be targeted later so it needs a name, let's call it relay_example. So in our case, there are 3 things we want to do to our texture: Make it start at the beginning, animate at 10 FPS, and then stop at the end. So to make it start at the beginning, we're going to fire the input SetTextureIndex, with a parameter override of 0, to the env_texturetoggle entity. This will look like:

OnTrigger -> tt_example -> SetTextureIndex -> 0 -> delay of 0.

Next we need to animate our texture, this is done by firing the input IncrementTextureIndex to the env_texturetoggle. However, we obviously need this to happen repeatedly in order to fully animate the texture, so we need to create a recursive I/O system to achieve this. This is done like the following:

OnUser1 -> tt_example -> IncrementTextureIndex -> <No parameter> -> delay of 0.
OnUser1-> relay_example -> FireUser1 -> <No Parameter> -> delay of 0.1.

The key thing to note here is that we are firing OnUser1, not OnTrigger, like we did with the SetTextureIndex input, this is to avoid the texture continually resetting to the start point whenever our recursive I/O fires. Also of importance is the delay of the 2nd input, this is your FPS. So with a delay of 0.1 seconds, this means we will get 10 frames a second. I'm not totally sure how precise map I/O is, but some values of significance are: 0.016 for 60 FPS, 0.0333 for 30 FPS and 0.0416 for 24 FPS.

The last entity we need to setup is a secondary relay to control our first relay, we need to fire 3 inputs to it to get our desired effect: FireUser1, Trigger, and CancelPending (with a delay). So it will simply look like:

OnTrigger -> relay_example -> FireUser1 -> <No parameter> -> delay of 0.1.
OnTrigger -> relay_example -> Trigger -> <No parameter> -> delay of 0.
OnTrigger -> relay_example -> CancelPending -> <No parameter> -> delay of 5

The only thing you need to pay attention to is the CancelPending delay (which is operating as the "stop" point of the animation), if you want to make the texture play once and then stop, this value is the Number of frames in the animation / FPS (or number of frames * delay). So if our animated texture has 50 frames, playing at 10 fps (meaning it's shooting frames once every 0.1 seconds) then the result end time is 5. Also note that we delay FireUser1 by our frame rate, otherwise our animation will essentially start on it's 2nd frame.

Lastly, all you need to do is give the secondary relay some name and then fire the Input Trigger to it from any other entity (a button, trigger multiple etc.) and watch the magic happen.

I hope this has been informative, I couldn't find any other guides on this. Also if you want to critique my explaining skills I encourage you to do so, I know my explanations are kind of verbose/wordy/hard to follow sometimes. You can download the VMF and BSP here to see what it looks like: BSP, VMF.
 
Last edited: