Vehicles (modeling)

From Valve Developer Community
Revision as of 06:42, 10 July 2011 by Lady-Natalya (talk | contribs) (Vehicle Animations: Added an image of a vehicle in MS3d showing the skeleton.)

Jump to: navigation, search

Collision model

All vehicles need a physics collision model. Your .QC needs a section like this (see Physics and Ragdolls for information on how to build the SMD for the collision model).

$collisionmodel "digger_physbox.smd"
     // Mass in kilograms
     $Mass 1600

To get started, you can simply use a copy of render model of the vehicle but make sure to remove the wheels. The actual collision model will be the convex hull of the render model in that case. You can visualize it by placing your vehicle in a level and using the command vcollide_wireframe 1 in the console.

Wheel Collisions

Next, we’ll set up the wheels. For best results, you’ll want to place attachment points in the .QC file for each wheel.

$attachment wheel_fl "Dummy04" 0 0 8
$attachment wheel_fr "Dummy03" 0 0 -8
$attachment wheel_rl "Dummy01" 0 0 8
$attachment wheel_rr "Dummy02" 0 0 –8

There are four wheels supported at this time. They are named with two letter codes:

  • fl "front left"
  • fr "front right"
  • rl "rear left"
  • rr "rear right"

You must name the attachments as above. It does not matter what order you add them to the .QC file however.

One important detail is that the wheels are modeled as spheres. For this reason, the wheels are pulled under the vehicle a bit. The origin of the wheel bones is actually the center of the wheel graphically, but in order to avoid having the spherical wheels poke out from under the car (thus brushing against things next to the car), each attachment is pulled in a bit.

For example, this would place the wheel sphere exactly over its graphical representation:

$attachment wheel_fl "Dummy04" 0 0 0

This is adjusted in by 8 inches.

$attachment wheel_fl "Dummy04" 0 0 8

The amount to pull them in depends on the size of the wheels and the collision model of the car. In this case, the wheels have a radius of about 22.5 inches and I’ve pulled them in by 8 inches. Using this ratio is a good starting point. You can visualize the wheels using "ent_bbox prop_vehicle" in the console if you build a map with your vehicle as a prop_vehicle.

Vehicle Animations

Your vehicle skeleton might look something like this. - Click to enlarge.

The vehicle requires a few animations.

  1. A sequence with the steering of the wheels. This can be only 3 frames (left, center, right) if you’d like. Be sure to note the exact angle that the wheels turn and make it consistent. You’ll need to put that angle into the vehicle’s script file so that the physics will match the animation.
  2. A sequence with the suspension animated. This can be only 2 frames (fully compressed, fully extended). This sequence determines the amount of travel each wheel has. So if you want to have a car be angled/jacked up, you’ll need to make the back wheels extend further than the front wheels.
  3. A sequence with all of the wheels spinning one revolution.

Because steering, suspension and wheel rotation are all animation you can map them to anything. You can animated flexing dune-buggy suspensions or counter rotating wheel pieces, etc. These won’t be simulated by the physics system, but they will appear to be simulated because they will be precisely coordinated with the simulation. You’ll need the following pose parameters to map the simulation onto the animation.

This controls the steering. –1 is left, +1 is right.

$poseparameter "vehicle_steer" -1 1

These control the height of each wheel (flex the suspension). 0 is compressed, 1 is extended.

$poseparameter "vehicle_wheel_fl_height" 0 1
$poseparameter "vehicle_wheel_fr_height" 0 1
$poseparameter "vehicle_wheel_rl_height" 0 1
$poseparameter "vehicle_wheel_rr_height" 0 1

These control the rotation of each wheel. +/- 180 degrees from neutral/base rotation.

$poseparameter "vehicle_wheel_fl_spin" -180 180 wrap
$poseparameter "vehicle_wheel_fr_spin" -180 180 wrap
$poseparameter "vehicle_wheel_rl_spin" -180 180 wrap
$poseparameter "vehicle_wheel_rr_spin" -180 180 wrap

Here’s an example .QC file that sets up the pose parameters.

$animation neutral "digger_idle" frames 0 0

$weightlist front_wheels { "Dummy03" 1.0 "Dummy04" 1.0 }
$animation turn_left "digger_turn" frame 0 0 subtract neutral 0 weightlist front_wheels
$animation turn_right "digger_turn" frame 2 2 subtract neutral 0 weightlist front_wheels
$sequence turning { turn_left turn_right blend vehicle_steer -1 1 } weightlist front_wheels delta autoplay

// front right
$weightlist wheel_fr { "Dummy03" 1.0 }
$animation wheel_fr_low "digger_suspension" frame 0 0 subtract neutral 0 weightlist wheel_fr
$animation wheel_fr_high "digger_suspension" frame 2 2 subtract neutral 0 weightlist wheel_fr
$sequence wheel_fr_suspension { wheel_fr_low wheel_fr_high blend "vehicle_wheel_fr_height" 0 1.0 } weightlist wheel_fr delta autoplay

$animation wheel_fr_spin0 "digger_wheelspin" frame 0 0 subtract neutral 0 weightlist wheel_fr
$animation wheel_fr_spin120 "digger_wheelspin" frame 3 3 subtract neutral 0 weightlist wheel_fr
$animation wheel_fr_spin240 "digger_wheelspin" frame 6 6 subtract neutral 0 weightlist wheel_fr
$sequence wheel_fr_spin { wheel_fr_spin0 wheel_fr_spin120 wheel_fr_spin240 wheel_fr_spin0 blendwidth 4 blend "vehicle_wheel_fr_spin" -180 180 } weightlist wheel_fr delta autoplay

// front left
$weightlist wheel_fl { "Dummy04" 1.0 }
$animation wheel_fl_low "digger_suspension" frame 0 0 subtract neutral 0 weightlist wheel_fl
$animation wheel_fl_high "digger_suspension" frame 2 2 subtract neutral 0 weightlist wheel_fl
$sequence wheel_fl_suspension { wheel_fl_low wheel_fl_high blend "vehicle_wheel_fl_height" 0 1.0 } weightlist wheel_fl delta autoplay
$animation wheel_fl_spin0 "digger_wheelspin" frame 0 0 subtract neutral 0 weightlist wheel_fl
$animation wheel_fl_spin120 "digger_wheelspin" frame 3 3 subtract neutral 0 weightlist wheel_fl
$animation wheel_fl_spin240 "digger_wheelspin" frame 6 6 subtract neutral 0 weightlist wheel_fl
$sequence wheel_fl_spin { wheel_fl_spin0 wheel_fl_spin120 wheel_fl_spin240 wheel_fl_spin0 blendwidth 4 blend "vehicle_wheel_fl_spin" -180 180 } weightlist wheel_fl delta autoplay

// rear right
$weightlist wheel_rr { "Dummy02" 1.0 }
$animation wheel_rr_low "digger_suspension" frame 0 0 subtract neutral 0 weightlist wheel_rr
$animation wheel_rr_high "digger_suspension" frame 2 2 subtract neutral 0 weightlist wheel_rr
$sequence wheel_rr_suspension { wheel_rr_low wheel_rr_high blend "vehicle_wheel_rr_height" 0 1.0 } weightlist wheel_rr delta autoplay
$animation wheel_rr_spin0 "digger_wheelspin" frame 0 0 subtract neutral 0 weightlist wheel_rr
$animation wheel_rr_spin120 "digger_wheelspin" frame 3 3 subtract neutral 0 weightlist wheel_rr
$animation wheel_rr_spin240 "digger_wheelspin" frame 6 6 subtract neutral 0 weightlist wheel_rr
$sequence wheel_rr_spin { wheel_rr_spin0 wheel_rr_spin120 wheel_rr_spin240 wheel_rr_spin0 blendwidth 4 blend "vehicle_wheel_rr_spin" -180 180 } weightlist wheel_rr delta autoplay

// rear left
$weightlist wheel_rl { "Dummy01" 1.0 }
$animation wheel_rl_low "digger_suspension" frame 0 0 subtract neutral 0 weightlist wheel_rl
$animation wheel_rl_high "digger_suspension" frame 2 2 subtract neutral 0 weightlist wheel_rl
$sequence wheel_rl_suspension { wheel_rl_low wheel_rl_high blend "vehicle_wheel_rl_height" 0 1.0 } weightlist wheel_rl delta autoplay
$animation wheel_rl_spin0 "digger_wheelspin" frame 0 0 subtract neutral 0 weightlist wheel_rl
$animation wheel_rl_spin120 "digger_wheelspin" frame 3 3 subtract neutral 0 weightlist wheel_rl
$animation wheel_rl_spin240 "digger_wheelspin" frame 6 6 subtract neutral 0 weightlist wheel_rl
$sequence wheel_rl_spin { wheel_rl_spin0 wheel_rl_spin120 wheel_rl_spin240 wheel_rl_spin0 blendwidth 4 blend "vehicle_wheel_rl_spin" -180 180 } weightlist wheel_rl delta autoplay

Driver's View

If the vehicle is drivable, you’ll also need to place an attachment point for the driver’s eyes.

$attachment vehicle_driver_eyes "view" 0 0 0

It must be named vehicle_driver_eyes.

Quick reference

As a quick animation reference of what needs to be animated, you'll need the following:

-suspension - 3 frames - frame0: lowest position of wheels; frame1: normal position of wheel; frame2: highest position of wheels
-turn - 3 frames - frame0: turn left; frame1: centered; frame2: turn right
-spin - 9 frames - frame0: wheels at 0 degrees; frame9: wheels spun forwards 360 degrees

If you have a mounted weapon (only takes into account 1 weapon):

-aim - 9 frames - frame0: weapon pointed left and aimed down; frame1: weapon centered and aimed down; frame2: weapon pointed right and aimed down; frame3: weapon pointed left and centered aim; frame4: weapon centered and centered aim; frame5: weapon pointed right and centered aim; frame6: weapon pointed left and aimed up; frame7: weapon centered and aimed up; frame8: weapon pointed right and aimed up

These animations are only what are needed for a basic driveable vehicle. Additional animations can be seen in sourcesdk_content\hl2\modelsrc\Buggy


Each vehicle requires a script to function properly. Nearly all the vehicle traits can be controlled via the script. A vehicle script which lacks a definition for any variable will simply default it's value based on the hard code. A variable placed in the wrong block will cause a fatal crash.

The script is broken down into separate blocks defining each set of traits.

		"massCenterOverride"	"0 0 0"
		"massoverride"		"800"
		"addgravity"		"0.33"
	Rest goes here...

This will define the basics of a body set up for the vehicle. Remember that if any of these were missing, they would default automatically. These settings are copied directly from the Source SDK's jeep_text.txt.

massCenterOverride will adjust the center of gravity in relation to the vehicle's local origin (as defined in the .MDL).

Mass and Gravity are distinctly different. Mass will cause the vehicle to become heavier, whereas Gravity will create downward force. You will need to compensate with Horsepower in either case. Mass is evident at all times, whereas Gravity is most apparant during uphill movement. Flat ground movement is unaffected.

Vehicles are overdetermined systems. There are many parameters that interact, so tuning them (especially randomly) can be difficult.

The offset is the distance from the origin to the axle. The wheeloffset is the distance from that point to each wheel. This get symmetrically reflected +/- around the axle origin for alternating wheels (which means only supports two wheels per axle).

Note:If you use wheel attachments on your model (wheel_fl, etc...), then the vehicle code will compute these values for you, so it is not necessary to have them in your script.

keepuprighttorque is not hooked up to anything.

tiltforce is the number of gravities to apply to the car when it rolls past a certain hardcoded limit.

tiltforceheight is an offset in the car's local space to move that additional gravity.

Together these two parameters attempt to simulate a different mass center when the car is rolling. countertorque is a scale modulates the torque at the wheels acting on the body.

Wheel mass affects the car body through the suspension.

massCenterOverride is very useful for preventing roll. Keep in mind that the car body is completely rigid and has uniform mass distribution. This is a poor model for real cars since they have most of their mass at the bottom (suspension) and very little in the cabin since it's mostly empty space. So generally you'll want to adjust this a little bit to avoid having the mass center go to the center of the car's collision shape. You can also artifically push this through the ground if you want a more hacked way to keep the car from rolling.

See also