Vscript 2 SMD generator (Portal 2)

What is it?

It's a Vscript that allows you to record entities in game and dump out an SMD animation file to console.

Uses include recording large physics explosions or replacing complicated movements driven by many entities.

Unfortunately this script can't currently be used with L4D2 as we don't have GetAngles or sv_script_think_interval to get above 10 FPS, however, generated animations can be used with any Source game.



How it works

Place a logic_script in a copy of your map (I usually call it mapname_phys.vmf). Technically it could be any entity that can run a script (which is most). This represents your model origin. For this example, I'll call it smd_script.

Set it's think function to Think and the Entity Script to this script (vscript2smd\phys2smd)

For every entity that you want to record, have it register with the logic_script. The easiest way to do this is add an output like this on each entity

OnUser1 > smd_script > RunScriptCode > RegisterProp()

I find it convenient to name everything that I will be recording with a common prefix such as sim_

So I can just "ent_fire sim* fireuser1" or trigger it from a logic_auto. Keep in mind that the initial position and angles will be recorded only when the entity is first registered.

So now that you have everything set up, you want to start recording and do whatever will cause your entity movement. I find it helpful to do this all with one trigger so I don't have a lot of empty frames at the beginning of the animation.

To start recording....

ent_fire > smd_script > RunScriptCode > StartRecord()

To end recording

ent_fire > smd_script > RunScriptCode > StopRecord()

If you're not happy with your "take", you can reset the initial positions by issuing

ent_fire > smd_script > RunScriptCode > Reset()

You may have to reset other entities depending on your scene.

Once you have a take that you like, you'll want to dump the SMD data. There are a few caveats. One, the console back buffer is small. An animation can exceed it's length quite easily. So the easiest way to do this is to enable console logging.

Enter con_logfile "yourlogname" in the console, now all console data will be logged.

Then dump your recording

ent_fire > smd_script > RunScriptCode > DumpRecord()

Often on large animations, you will get an error message on the first dump saying the script was suspended for taking too long, don't worry about it, just issue the command again. You should see a lot of txt fly by, ending with the attachment points (bones and attachments are named after the props)

OK, now what?

Open the logfile you created in the portal2 directory (with con_logfile) and search for the SMD data, it will look like this...

//Dumping 37 frames!--------------
//START SMD DATA DUMPING ANIM frames [0] to [100000]
//INIT_POS is (vector : (14605.700195, -378.209015, 1158.109985))
version 1
nodes


You need to grab everything from version 1 until the last frame which have the following line after it.

//END SMD DATA 


You can include those lines with no harm as they are commented out. If you dumped multiple takes make sure you only grab one. Note the attachment data that follows, you'll need that for the QC.

Copy and paste this into a new file, for this example, call it anim.smd

Now we need to make a QC to compile the model. Make a new file in the same directory as the SMD file.

Let's call it test.qc, you want it to look like this

$modelname "vscript2smd/YOURMODELNAME.mdl"
$origin 0 0 0 270 
$hboxset "default"

// change "anim" to whatever you named your smd file // but don't put the extension! $sequence idle "anim" act_idle 1 fps 10.00{} $sequence anim "anim" fps 30.00{} // 30 is default but changeable

//PASTE generated $attachment data here!


Compile the model for the target game via studioMDL or GUIStudioMDL

Using it in-game Now take the map and save it as mapname_smd (or whatever you like).

Change the logic_script to a prop_dynamic and load your generated model. Change it's entity script to

vscript2smd\parent_me

Change your physics props and brushes to their dynamic counterparts.

So func_physbox would become func_brush and prop_physics would become prop_dynamics, etc. Keep their names the same.

You can actually select all of your prop_physic's at once and mass change them but this doesn't work for func_physbox or other brush entities as it will lose the entity name (which is needed and must be exactly the same as when you generated the smd). A cheat would be to open up your map in a text editor and search and replace func_physbox to func_brush (though if you want to keep some unrelated func_physbox's it won't work)

Once you're done, just make sure you fireuser1 on all of your simulated props on map load or at some point before the animation plays

ent_fire sim* fireuser1 (or a logic_auto), this will make the entities parented to the model and set their attachment

To animate, simply set it's animation to whatever you called it and trigger the appropriate sound and/or particle effects.

Oddities and warnings

Do not set Prop Data on physbox's. In my experience this will cause them to break no matter what, and an entity disappearing during recording will bork it.

Gravity in a map that has only been through vbsp seems totally different than one that has had vrad run.

Other thoughts

While you won't have the lag of a bunch of physics props, it doesn't help with entity count. You could export your brushes out as models via Propper, and combine/envelope them in XSI/Blender. I've contacted the author of Propper about making this pretty much automatic, hopefully he's amenable to the idea. Because who wants to manually envelope dozens of bones

In the future, I'd like to add impact sounds that get added to the QC automatically. Many of my other planned additions have been negated by the release of Source Filmmaker

Download

vscript2smd version 1

Save it to your portal2 vscripts directory and unzip

Example VMF

vscript2smd-example-vmfs.zip

Scroll to top