Viewmodels in XSI
In this article you will learn how to create a view model for Source using XSI.
Contents
Camera Setup
Start by positioning the camera in XSI to show a similar view as what the player will see in the game. There are two methods to accomplish this:
- Set a 54 degree F.O.V. perspective camera at origin 0,0,0 facing down the Positive Z axis.
- Set a 54 degree F.O.V. perspective camera at origin, using the coordinates shown below, facing along the Positive Z axis. Use the QC command $Origin 0 0 68 to compenaste. (This is useful when merging in character rigs to animate, otherwise it is recommended to use example A)
The Source engine supports any F.O.V., but using 54 (which is close to the human eye) will enable modeling a weapon to correct scale without it appearing distorted in the engine. Source actually uses a dual F.O.V. system. In Half-Life 2 the world is rendered at 75 F.O.V. while weapons are rendered at 54.
Positioning
If it's not in the scene already, merge/import a weapon mesh. Position the weapon where it looks best in the camera view. To position the weapon correctly, move the weapon mesh and not the camera.
Do this before finishing the model because it helps to show where to best spend on polygons: as can be seen below, the front of the shotgun mesh at A has detail near the barrel that is not seen from the camera. Those polygons would could be better used up near the handle or simply deleted.
Merging texture coordinates
In this example, the shotgun and arms have been modeled and textured separately (it is necessary to step into the world of imagination and pretend that this example is textured). Viewmodel weapons need to consist of a single mesh, which requires merging both the shotgun and arm meshes together while keeping the texture coordinates intact. Do to this, merge the arm mesh into the scene File > Merge
, next, under the Model
panel select Poly Mesh > Merge
. The dialog box seen below will appear.
Generally the tolerance should be set to 0. The tolerance will weld verts that are close to each other. The higher the tolerance number, the more verts will be welded together. This is handy when stitching two models together, such as modeling one side of an object, duplicating and mirroring it and then welding it back to the original. For this example, however, none of the hand verts should be welded to any of the weapon verts. Click the All button to merge all materials and texture coordinates into a new single mesh.
XSI creates a new mesh after the merge, "Polymesh". Freeze the new mesh before deleting the old ones. You now have a single mesh with merged UVs.
Rigging
Now attach the mesh to the rig. Although the example shown used a rig with fully articulate fingers to pose the player's hand gripping the gun (A), the final version will use a single bone to control the rotation and translation of the hand and shotgun (B). High bone counts can be very costly and unlike characters, the view model can't take advantage of bone L.O.D.s because they are always close to the player's viewpoint. Should it be necessary to see fingers move (to pull the trigger, for example) then add one bone to the scene that is a child of the hand-bone.
The gun holding hand usually consists of three bones. One for the elbow, one for the hand and and one for the gun. Because the hand will never let go of the shotgun handle, this example will only have two bones (elbow and hand). In the case that the weapon has moving parts, it will be necessary to have extra bones parented to the gun.
Plan ahead before creating a rig for the weapon. If it turns out that none of the requisite animations require the right hand to ever let go of the handle, don't put bones in all of the fingers of the right hand (as described above).
Rig the left hand depending on the needed animations. For this shotgun, the left hand needs to be fully articulate for the reload animation. In the image below all of the fingers have bones, but it would have been more efficient to merge last two fingers into the same bone control.
Once rigged and animated, delete any faces that are not seen in the camera viewport. Re-export the reference file smd. In the below example the faces from the elbows to the shoulders have been deleted. Other areas to look at would be the right-bottom forearm, the back of the right hand, and the right side and underneath of the shotgun.
Editing the QC file
Below is this example's QC file. Following are some of the commands that are a little less straight forward:
- $Origin 0 0 68
- As stated above, this command compensates for animation of the weapon at the players eye-height in XSI
- $Attachment
- The muzzle attachment, for example, dictates where the muzzle flash sprite/effect occurs. One easy way to create Attachments is to parent a null to a bone in XSI. Be sure to export with the option of keeping unused bones if you do this!
- Nodes
- Nodes are used to tell the character what state it is in. In the below example the nodes are used to tell the weapon whether or not it is pointed at a friendly NPC or not (In HL2, the weapon is lowered when pointed at friendly NPCs). If this feature isn't needed, simply exclude all node commands from the weapon.
$modelname weapons/v_shotgun.mdl $body studio "Shotgun_reference.smd" $origin 0 0 68 //Muzzle flash $attachment "muzzle" "ValveBiped.Muzzle" 0 0 0 rotate -90 0 0 rigid //Shell eject $attachment 1 "ValveBiped.Eject" 0 0 0 rotate 180 0 0 rigid $sequence idle01 "Idle01" loop fps 30 activity ACT_VM_IDLE 1 node 0 $sequence fire01 "Fire01" fps 30 snap activity ACT_VM_PRIMARYATTACK 1 { event AE_MUZZLEFLASH 0 "SHOTGUN MUZZLE" } node 2 $sequence altfire "Alt_fire01" fps 30 snap activity ACT_VM_SECONDARYATTACK 1 { event AE_MUZZLEFLASH 0 "SHOTGUN MUZZLE" } node 2 $sequence draw "Draw" fps 30 snap activity ACT_VM_DRAW 1 node 0 $sequence holster "Holster" fps 30 activity ACT_VM_HOLSTER 1 node 0 $sequence reload1 "Reload_start" fps 30 activity ACT_SHOTGUN_RELOAD_START 1 node 0 $sequence reload2 "Reload_load_shell" fps 30 activity ACT_VM_RELOAD 1 node 0 $sequence reload3 "Reload_finish" fps 30 activity ACT_SHOTGUN_RELOAD_FINISH 1 node 0 $sequence pump "Pump" fps 30 activity ACT_SHOTGUN_PUMP 1 { event 6001 5 "2" } node 0 $sequence dryfire "Dryfire" fps 30 activity ACT_VM_DRYFIRE 1 node 2 $sequence lowered "Non_threat_idle01" loop activity ACT_VM_IDLE_LOWERED 1 node 1 $sequence lowered_to_idle "Non_threat_to_idle01" activity ACT_VM_LOWERED_TO_IDLE 1 transition 1 0 $sequence idle_to_lowered "Idle01_to_non_threat" activity ACT_VM_IDLE_TO_LOWERED 1 transition 0 1