UT Vertex Animations From MilkShape
This tutorial is specific to MilkShape for making models and importing them into Unreal Tournament.
Create a Kickass Model
Find a good tutorial on modeling with MilkShape. Once you have successfully created your mesh, including texturing and animation, you're ready to go on to step 2.
Export Your Mesh to Unreal Format
In order to get your model into unreal you must first prepare for it. This involves creating a package which is a little complex, but gets easier with time.
First off, you need to set up your folders so Unreal will know where to look for them when we tell it to make our package.
Under your UnrealTournament folder, create a new folder with the name of your package (or what it will be, e.g. "MyCustomGuns"). Then, under your package folder place new folders with the following names: Classes, Models, Textures, which are required, and some non-required folders like Sounds(but you have to make new sounds and import them with code).
- Also worth noting, packages can contain more than one class in them so any other models you make using this tutorial can be placed within the same package... but beware of size if you plan to distribute.
After you have exported your model into the UT format – (that is the _a.3d and _d.3d files from the export list of MilkShape), save them in the Models folder you just made under your package folder.
- At this point, you may want to use UnrealFX to spice up your model. It allows models to be set to special face flags, one poly at a time. E.g. You could make a particular surface environment mapped, which makes it shiny once ingame.
Once you export from MilkShape you'll end up with 2 files ending with .3d. (One will end with _a.3d and the other with _d.3d). MilkShape also makes a .uc file, but it is no where near complete. You will definitely need to edit this but it is a good base.
Importing Your Model
Now modify the .uc file for importing the mesh into Unreal Tournament. (Or make a new one if you are able. If you want to have a look at an .uc file that's properly set up for mesh importing, check one that was generated by MeshMaker.)
This can be created or edited in any text editor. (I use Notepad cause it's simple, but there are many other programs you can use.) Move or save this .uc file in your Classes folder that is under your package's folder. This is what it should look like.
class testGun expands Actor; #exec MESH IMPORT MESH=myGun ANIVFILE=MODELS\gun1_a.3d DATAFILE=MODELS\gun1_d.3d X=0 Y=0 Z=0 #exec MESH ORIGIN MESH=myGun X=0 Y=0 Z=0 #exec MESH SEQUENCE MESH=myGun SEQ=All STARTFRAME=0 NUMFRAMES=25 #exec MESH SEQUENCE MESH=myGun SEQ=Still STARTFRAME=0 NUMFRAMES=1 #exec MESH SEQUENCE MESH=myGun SEQ=Fire STARTFRAME=1 NUMFRAMES=20 #exec MESH SEQUENCE MESH=myGun SEQ=Reload STARTFRAME=21 NUMFRAMES=5 #exec MESHMAP NEW MESHMAP=myGun MESH=myGun #exec MESHMAP SCALE MESHMAP=myGun X=1 Y=1 Z=.5 #exec TEXTURE IMPORT NAME=myGunTex1 FILE=TEXTURES\guntex1.pcx GROUP=Skins FLAGS=2 #exec TEXTURE IMPORT NAME=myGunTex1 FILE=TEXTURES\guntex1.pcx GROUP=Skins PALETTE=myGunTex1 #exec TEXTURE IMPORT NAME=myGunTex2 FILE=TEXTURES\guntex2.pcx GROUP=Skins FLAGS=2 #exec TEXTURE IMPORT NAME=myGunTex2 FILE=TEXTURES\guntex2.pcx GROUP=Skins PALETTE=myGunTex1 #exec MESHMAP SETTEXTURE MESHMAP=myGun NUM=1 TEXTURE=myGunTex1 #exec MESHMAP SETTEXTURE MESHMAP=myGun NUM=2 TEXTURE=myGunTex2 defaultproperties { DrawType=DT_Mesh Mesh=myGun }
It may be difficult to see what's going on here, so let's take a look at all of the types of statements you'll need in your file.
Class Definition
class MyGun expands Actor;
Ok, this is a problem. When MilkShape made .uc file it didn't know anything about what you wanted out of your mesh, so it just set it up to expand (or acts as) a generic Actor. This is rarely (if ever) what you'll want when you get to the point of really using your mesh for something (like for a weapon or character). Even if it's just a Decoration, you'll want to change this. For now just set this field to expand UT Decoration, you won't be able to use it as a weapon, but you'll know its ingame and see it in the mesh viewer.
For now, replace "MyGun" with what you want to call your new object. Do not include any spaces. (This new object name must also match the name of the .uc file or you will get an error when compiling, so save the .uc file as the same name.)
Mesh Import
#exec MESH IMPORT MESH=myGun ANIVFILE=MODELS\mygun1_a.3d DATAFILE=MODELS\mygun1_d.3d X=0 Y=0 Z=0
This one's easy. Just replace the _a.3d and _d.3d names with the names of your .3d files and the mesh name to whatever you like, e.g. "MESH=Pistol". This tells the Unreal compiler where to find your .3d files. In this example, the .3d files would be stored in the Models folder under your package folder.
Origin Definition
#exec MESH ORIGIN MESH=myGun X=0 Y=0 Z=0
For most items like weapons or pickup items, you'll want to just leave this statement as is, except for changing the mesh name. The MESH ORIGIN statement sets up where the center of the mesh is. In other words, the point where your mesh will rotate around and move from, as well as the center of its mass and is used in colision detection.
You can also use the MESH ORIGIN statement to set the initial rotation values of your mesh. If you've modeled a weapon and it ends up facing the wrong direction in the game, you can fix that here. You do that by adding PITCH, ROLL, and/or YAW values to the statement. The values aren't normal angles though as the unreal engine relies on a system using of multiples of 16 units. A value of 64 means 90 degrees, a value of 128 means 180 degrees, 256 means 360 degrees, etc. So this statement:
#exec MESH ORIGIN MESH=myGun X=0 Y=0 Z=0 PITCH=32 ROLL=128 YAW=-64
...would mean a pitch of 45 degrees, a roll of 180 degrees, and a yaw of -90 degrees. Also, when MilkShape exports the models are usually off by 90 degrees of yaw, I almost always have to set it to YAW=64 or -64.
Animation Sequences
#exec MESH SEQUENCE MESH=myGun SEQ=All STARTFRAME=0 NUMFRAMES=25 #exec MESH SEQUENCE MESH=myGun SEQ=Still STARTFRAME=0 NUMFRAMES=1 #exec MESH SEQUENCE MESH=myGun SEQ=Fire STARTFRAME=1 NUMFRAMES=20 RATE=24 #exec MESH SEQUENCE MESH=myGun SEQ=Reload STARTFRAME=21 NUMFRAMES=5 RATE=7.5
If your mesh includes animation (even some Decorations do), you'll need to name your animation sequences in these statements. When MilkShape generates .uc files it is does not know which sequences go where as it is all one line of anims to it. Usually, the first sequence name is called "All" and simply includes all of your animation frames. Create a MESH SEQUENCE statement for each of your animation sequences and name them something descriptive. You can also add a "RATE=" statement to the end of the anim seq line. This sets up how long it will take to play the sequence, in frames per second (unless it is only 1 frame long). MilkShape by default uses 24 fps so a RATE of 24 will set animations to the same speed as in MilkShape.
The animations should have been made in MilkShape as one long animation of all the sequences one after another (this gets to be a large file if making a player model). While making your model, since all the sequences will run together, it is good to write down the sequences as well as their starting frame number, and their length of frames.
If your mesh does not include any animation, you can just use something like this (which is good for weapon pickup and third person view meshes).
#exec MESH SEQUENCE MESH=myGun SEQ=All STARTFRAME=0 NUMFRAMES=1 #exec MESH SEQUENCE MESH=myGun SEQ=Still STARTFRAME=0 NUMFRAMES=1
Meshmap to Mesh Associations
#exec MESHMAP NEW MESHMAP=myGun MESH=myGun
This must match as it tells the compiler which uv mapping coordinates to use with your mesh, it will not compile if incorrect. I suggest leaving this as is because it is correct this way, just swap the name here with your class name. (...see a pattern? everything must represent the name of your class.)
Meshmap Scaling
#exec MESHMAP SCALE MESHMAP=myGun X=1 Y=1 Z=.5
Scaling is an important concept to understand. The way that MilkShape's "units" relate to Unreal units is easy – 1:1... as in 1 MilkShape unit will become 1 Unreal unit. That way if you treat 16 units in MilkShape as 1 foot (as it is in UT, roughly), you should be able to set your scaling to "X=1 Y=1 Z=.5". The Z axis of meshes is always half of the others in UT.
Texture and Palette Import
#exec TEXTURE IMPORT NAME=myGunTex1 FILE=TEXTURES\guntex1.pcx GROUP=Skins FLAGS=2 #exec TEXTURE IMPORT NAME=myGunTex1 FILE=TEXTURES\guntex1.pcx GROUP=Skins PALETTE=myGunTex1
For every new Texture (UT) image that your mesh uses, you'll need a line to import it. Give it a descriptive name in place of "myGunTex1" and fill in the name of your .pcx file. In this example, the .pcx files would be in the Textures folder under your package folder. Some people put textures in the models folder but I do not, that is what the Textures folder is for.
Note: The height and width of your textures need to be "powers of 2." In other words, both the height and the width need to be one of these numbers: 1, 2, 4, 8, 16, 32, 64, 128, or 256. You can go higher (512, 1024, etc), but that doesn't seem to be typical when using the Unreal engine (yet). The height and width do not need to be the same, so a 64 x 32 image is fine, even a 256 x 2 is allowed if you need it.
Meshmap to Texture Associations
These statements associate the UV mapping of your mesh with specific textures. In MilkShape, you will get one of these for each Group you create. Each Group will be a "surface" that is numbered 1, 2, 3, etc.. The "NUM=1" line says to associate the first surface with the myGunTex1 texture. NUM=3 shows how you can use the same textures over again on different groups.
Since the maximum number of surfaces allowed is 8, you would never have more than 8 of these statments per mesh.
Default Properties
Setting the default properties correctly is very important.
defaultproperties { DrawType=DT_Mesh Mesh=MyGun }
DrawType simply tells the engine that you want this to be a mesh. Most models will be "DT_Mesh". (Except for effects, they will normally use "DT_Particle" but use a mesh for the vertex location and animation).
Remember to save your .uc file in the Classes folder under your package folder and name it the same as the class. The example here would have been named MyGun.uc.
Adding Code
If you already have the code, you can add it to the .uc file to tell UT what you want your model to actually "do" or "be" ingame.
Currently, your mesh is just a 3D object with no properties or behaviors. You'll typically want to use your mesh as a weapon, character, pickup item, or at least something you can interact with in some way. The way to do that is by scripting your .uc file so that it "expands" on an existing type of object, such as TournamentWeapon (for weapons), Pawn (UT) (for players or creatures or inanimate things that are interactive), or Decoration (for stuff like furniture). Each type of object that you can create (there are many), has a set of properties that you can set. One of the properties you can set is which mesh (or meshes) to use. Some objects may have multiple meshes associated with them. For instance, a weapon has a "first person" version of the mesh that includes the player's hand and part of his arm, as well as a "pickup" version that is used to show that weapon sitting on the ground (rotating?) and a "third person" view which is what other players will see you carrying. (maybe with a small set of anims of its own.) The field labeled "Mesh" ("Mesh=MyGun") is the model that will show up in the Mesh Viewer in UnrealEd.
Here's an example. The part in quotes after LodMesh would be the reference to your mesh (which can be imported seperately in another .uc file).
class MyGun extends Decoration; defaultproperties { bCanBeBase=True ItemName="Colt Peacemaker" Mesh=LodMesh'MyCustomGuns.MyGun' CollisionRadius=18.790000 CollisionHeight=6.750000 Mass=10.000000 Buoyancy=15.000000 }
Import It Into the Game!
When you have your .uc files, your .3d model files, and your .pcx texture files in place, you're ready to actually import your mesh into your package, so that it's ready to use in Unreal Tournament.
- First, delete the .u package file with the name of this package(if it already exists) from the \UnrealTournament\System folder.
- Next, go in your UnrealTournament\System folder and find the file called UnrealTournament.ini and scroll down or search for the line beginning with "[Editor.EditorEngine]" then scroll down the lines below it untill you hit "EditPackages" and at the end of that list, add a new editpackage with your package name.
- For example, "EditPackages=MyCustomGuns" then save the .ini file without changing anything else.
- Now in a command prompt (MS-DOS prompt) in the \UnrealTournament\System directory type in "ucc make" (or under your start menu, choose "run" and type "C:\UnrealTournament\System\ucc make" if thats the location of your UT folder).
- You will then see a dos window pop up and load a list of all the packages listed in the UnrealTournament.ini file untill it gets to your package name, then it will proceed to load the components from the folders you made.
If you've done everything right, and you recieve no errors or warnings, your mesh is ready to go. Fire up UnrealEd and check it out in the mesh viewer.
For more help with using the UCC pragram, see Compiling With UCC.
Oh yeah, for weapons, you may need to delete your .u package file and adjust the alignment in your .uc file then re-compile quite a few times to get it right so don't be discouraged, you will learn it with practice and keeping notes.
(To align your weapon's first person view, just add the line PlayerViewOffset in default properties (either in the .uc before a re-compile or in advanced options ingame by typing "preferences" in the console) and give a value for each of the X, Y, and Z coordinates. Z being up and down in Unreal. And remember, PlayerViewOffset manipulates your perspective of the weapon, not the actual weapon!)
Tarquin: Probably. We could perhaps clean this area up. Some questions, which we should answer & discuss on the page MilkShape:
- what pages do we have on MilkShape?
- how should we organize them?
- what should we call them?