====== Porting From ArmA 2 to ArmA 3 ====== [[https://www.pmctactical.org/forum/viewforum.php?f=68|ArmA 3 Forum]], [[:arma3|ArmA 3]], [[arma3:config|ArmA 3 Config]], [[arma3:missions|ArmA 3 Missions]], [[arma3:modeling|ArmA 3 3D Modeling]], [[arma3:scripting|ArmA 3 Scripting]], [[arma3:terrain|ArmA 3 Terrain]], [[arma3:texturing|ArmA 3 Texturing]], [[arma3:tools|ArmA 3 Tools]] **Porting Models from ArmA 2 to ArmA 3 Tutorial** by Varanon, Community Upgrade Project (CUP). ====== Introduction ====== CUP's goal is to take ArmA 2 assets released by Bohemia Interactive, and bring them into ArmA 3, adding specific ArmA 3 features to the assets along the way. For a lot of people, this seems to be a scary thought at first. Where to start ? What to do ? People feel lost. This guide is trying to show you how this is achieved. And for the record, you need little to no knowledge about modeling, despite what you might think. ====== About this Guide ====== This guide will walk you through all the steps required to get a model into ArmA 3, including the associated config work and model modifications. To make this as practical as possible, we will take an existing ArmA 2 asset, the armed Pickup used by the NAPA and ChDKZ. ====== What we need... ====== First of all, make sure the ArmA 3 Tools are installed. You can get them from Steam's Tools tab. Secondly, you will also need Mikero's tools. Additionally, if you (like me) don't want to work in ObjectBuilder, you should install Blender and Alwarren's Blender toolbox. See the appendix for links to all these tools. You might be able to do all of this in ObjectBuilder, or another 3d Modeler if you want to, but I use Blender because the Arma Toolbox offers some additional functionality which will come in handy later. The guide will assume you use Blender. ====== Gathering the files ====== The first thing we always do when starting a new asset is classifying it and creating an appropriate directory. The Pickup (PK) from ArmA 2 is a Datsun. To find out the exact model name, we search for Pickup_PK_Ins (the class name from ArmA 2) and look for the line "//model=//". The string after this is the name of the model. **WARNING: Some models from ArmA 2 have been updated in ArmA 2: Operation Arrowhead. This means that there might be an overriding config entry in the expansion’s configs.** The Pickup (PK) is called Datsun_Armed, and it's model is located in //Wheeled_E\Datsun_Armed//. Since it's a wheeled vehicle, we create a new directory in CUP's //WheeledVehicles// folder, calling it //CUP_WheeledVehicles_Datsun//. All the files we will be gathering will go into this. First, we copy the model, //datsun_pk.p3d//, to the output folder. Rename it to //CUP_datsun_pk.p3d//. **VERY IMPORTANT**: Renaming the model with a CUP_ prefix is an important step. Models are later on referenced by file name in the //model.cfg//. These might clash with existing models in ArmA 3. For example, the SUV in ArmA 3 is called //suv.p3d//, the same name as the SUV in ArmA 2. Depending on whether the ArmA 3 or the ported ArmA 2 model is loaded first, skeletons might get mixed up and you will get strange animations on one or both of the similar named models. Next, copy the Data folder. This usually contains the //.rvmat// files that are used to determine surface characteristics and textures of the model. Finally, copy the **'model.cfg'**. We first deal with the model and the textures, so we skip //config.cpp// for now. ====== Importing into Blender ====== Start up Blender and select "//File – Import - ArmA 2/3 .p3d//", and select the //CUP_datsun_pk.p3d// file to import. It's a good idea to immediately safe the file under a different directory outside of the CUP tree (I keep all my //.blend// files in one directory). ====== First step: Obtaining textures ====== If you loaded the model into ObjectBuilder and subsequently Buldozer, you would notice that the model is white and no textures are shown. This is because the model references textures by their full path relative to the P:\ drive. The //.p3d// file references textures and materials (//.rvmat// files). The latter are included in the official released data. The former are not. Luckily, the texture files can be extracted from the ArmA 2 data files. If you set up a P:\ drive via mikero's tools for ArmA 2, it will already have extracted them. Which textures we need is determined by two sources: The model will reference texture files and .rvmat files, and the .rvmat files in turn will reference texture files. Remember that the data folder we copied earlier already contained most of the specific .rvmats for the model. Some will be in general directories (like for example //ca\ca_e\data\car_flare2.tga//) and might or might not have ArmA 3 equivalents. Refer to the CUP Wiki page ([https://dev.withsix.com/projects/cup/wiki/Common_Files_between_A3_and_CA here]) for more details. We start with the model itself: In Blender, make sure the right side toolbar is open (press the 'T' key if not), and select the 'Arma' tab. In the Arma Tools rollout, you will see an item called "Path Rename". Click on what you want to rename, and then enter a new name in the lower of the two string gadgets, then click on "Path Rename" to rename it. Go through the list and rename everything. If you hit a model specific texture, it will tell you where to copy it from. Copy the texture from the //p:\ca// tree to the data directory. Let's clarify this step with an example from the Datsun model. One of the textures specific to the Datsun is //ca\wheeled\data\datsun_interier_co.tga//. We want to copy that texture to our own directory. So, find the texture in //p:\ca\wheeled\data// and copy it over to //CUP\WheeledVehicles\CUP_WheeledVehicles_Datsun\Data//. Then, rename the texture as described above from //ca\wheeled\data\datsun_interier_co.tga// to //CUP\WheeledVehicles\CUP_WheeledVehicles_Datsun\Data\ datsun_interier_co.tga//. Repeat this process for each texture in the list. **Note:** ObjectBuilder has a similar functionality. Select Tools – Mass Texture & Material renaming. Next up, rvmat files. These are text files which in turn reference texture files again. Luckily, relocating them is relatively easy: Either use MoveObject, or use the appropriate function in the ArmA 3 Toolbox within Blender. Since the Blender Toolbox uses an internal list of textures that are specific to CUP, we'll use that one. Select the output folder, then select the rvmats one by one and click on Relocate RVMat. Once you're done with this, it's a good time to check if your model works correctly. Export from Blender as a //.p3d// and open the model in ObjectBuilder. Then, start buldozer. If you get any errors at this point complaining about missing textures or rvmat, go back and correct them. You either have a wrong path somewhere, or did not copy the texture/rvmat. **Tip:** If any texture is missing, you will find a complete list in the buldozer's RPT file, located at //c:\User\\AppData\Arma 3\bulldozer-XXXX.rpt//. The XXXX correspods to the date and time buldozer was started. If in doubt, sort by date and pick the newest file. One more step before we move on: All vehicles must have map icons and a picture. These are usually referenced in the config.cpp file as entries picture and icon. Go ahead and find those, and copy them to "//Data\UI//". ====== Moving onwards: Renaming Proxies ====== Buldozer might also have complained about missing proxies. Proxies are placeholder in the actual model that will be replaced by other models. A good example for a proxy is a missile attached to a plane's outer pylons: The missile itself is not part of the model, it's represented by a proxy that is replaced by the actual missile model. Proxies need to reference models by their full path relative to the root of the filesystem (in our case, the P:] drive). Renaming proxies can be done in ObjectBuilder, too, but the method I am explaining here assumes again that you use Blender for the process. Open the properties panel (press N if it's closed). Now, shift-select all Layers in Blender. The p3d importer puts each LOD on a different layer as a new object. Now, select the object named '1' in the outliner. On the properties panel, you will see a rollout called "Proxies". Some of them have a small "ghost" icon in front: Those are proxies for crew positions (drivers, pilots, gunners, cargo, etc). You can use any of the proxies present in //a3/data_f/proxies//, it doesn't matter which one you chose. The actual pose is determined later by the config.cpp. It will, however, look wrong in Buldozer, but you can safely ignore that. The others need their paths adapted. Some of the common proxies, like muzzleflashes and Capture-The-Flag type flags have ArmA 3 equivalents. Again, refer to the Wiki for an up-to-date list of those. To select a new model for a proxy, click on the small file select box next to the path name. Navigate to //P:\a3// or //P:\CUP// to find the correct proxy. Note that the same proxy might appear on more than one LOD including the special LODs like fire geometry etc. To make renaming those easier, copy the path from one proxy, and paste it into the appropriate other proxy paths. Don't mind the p:\ prefix or //.p3d// suffix, it gets stripped outomatically later. Repeat this for all proxies in the model, and then export it again. Check in Buldozer. ====== Now for some text editing: model.cfg ====== We've copied over //model.cfg// earlier, now we need to modify it to suit the new standard. First of all, we renamed the model, so this has to be reflected in the //model.cfg//, by adding the CUP_ prefix in front of the names. In this case, //datsun_pk// became //CUP_datsun_pk//. This applies to cfgSkeleton as well as the //cfgModel//. Remember that the cfgModel entry references the skeleton name. If you preview this in Buldozer, you can see the animations and confirm that they are working. ArmA 2 models don't usually support all the animations present in ArmA 3. Some might be missing, like, in our example, the dampers (the wheels can't contract to cope with terrain). Simply inherit those from the base class (check out //wheel_1_1_damper// in the sample data). We will revisit model.cfg in a later section again. ====== The meat: config.cpp ====== Now, we need to create the initial //config.cpp//. In CUP, we usually adopt a modular approach. The //config.cpp// is basically just a front-end: #include "basicDefines_a3.h" #include "CfgPatches.h" #include "CfgMoves.h" #include "CfgVehicles.h" The first thing to notice is that we are using //.h// as a file ending for included files, not //.hpp// as some other addons use. The reason is files size: While the resulting //config.cpp// will contain all the included files when binarized later on, binarize will also add //.hpp// files to the pbo, and that means the pbo will become cluttered with unnecessary files. Therefore, we avoid this by using a file name that is not included into the pbo. The file //basicDefines_a3.h// contains a number of defines that make things more readable, like defining the boolean constants true and false, and similar constants. //CfgPatches.h// contains the addon header: class CfgPatches { class CUP_WheeledVehicles_Datsun { units[] = {"CUP_Datsun_Pk"}; weapons[] = {}; requiredVersion = 1; requiredAddons[] = { "A3_Soft_F", "CUP_Weapons_Ammunition", "CUP_Weapons_VehicleWeapons" }; }; }; //CfgMoves.h// contains animations used for the vehicle. More on that later. Finally, //CfgVehicles.h// contains the actual definitions of the vehicles. For our first steps in game, we remove the line including //CfgMoves.h// by either deleting it, or better, putting a comment in front, two slashes: // this is a comment We're now ready to create the configuration for the Datsun. ====== Creating CfgVehicles.h ====== First of all, locate the original //config.cpp//. This is usually found where you copied the model from, but not always. Sadly, there's no real default place to search for, so you might need to look through some of the //ca\// data to find it. Also, some changes might have been introduced with Operation Arrowhead. If in doubt, check the directories ending in //_e// first, as there are the ones from the expansion. For the Datsun, the //config.cpp// is in //ca\wheeled\Datsun_Armed\config.cpp//, but an overriding base class is defined in //ca\wheeled_e\Datsun_Armed\config.cpp//. This redefines some of the damage textures. Going over each config item is way beyond the scope of this document, so I will present the finished //cfgVehicles.h// in the sample data files as //cfgVehicles.h-orig// (this will contain the parts "salvaged" from the ArmA 2 config. Along the way, we also created a //sounds.h// which contains just the sound definitions. The easy way for this is to take the one from the sample car and later on rework it. We'll go over this work later. ====== The first test: Packing the PBO ====== We're now ready to try. Launch Mikero's pboProject (assuming you have it installed), and select as output folder your mod folder where CUP is going to reside (for me //c:\Arma 3 Addons\@CUP-Work//), select the source folder (//p:\CUP\WheeledVehicles\CUP_WheeledVehicles_Datsun//), make sure "Full Build" is ticked, and crunch... If there are any errors, correct them (pboProject should tell you of the nature of the error). Then load up ArmA 3 with the //@CUP-Work// mod added, open the editor, and try to place the Datsun. Of course, you will notice that the thing handles like it's made from rubber, but we're going to fix that soon. Also, the crew animations are wrong. This is our next step. ====== Things that move: Animations ====== If you check the original //config.cpp//, you will notice these lines: driverAction = datsun_driver; cargoAction[] = {Hilux_cargo01,datsun_cargo02,MH6_Cargo03}; ... gunnerAction = "datsun_Gunner01"; gunnerInAction = "datsun_Gunner01"; These are the animations used for the driver, the passengers, and the gunner. We need to find those and copy them over to our data set. To store them, we create a folder called "//Anim//" inside the "//Data//" folder and gather the required files there. To find out what file to copy, we need to find the config entries for the appropriate actions. Again, there is no set rule where to look for them. If in doubt, use the Windows search function or a text search command line tool like grep. Watch out for file like "//CrewAnimations.hpp//" in the appropriate directory ("//wheeled//" or "//wheeled_e//" in our case), those are likely to have them. This is the case with the Datsun we're currently converting. You will find the animations in two classes: //CfgMovesBasic//, and //CfgMovesMaleSoldier//. The latter one contains the filenames, so we copy the //.rtm// files over to our own //data/anim// folder. Note that you also need to copy over the //KIA_*.rtm// files, they represent the stance of the crew when they are dead. You will also notice that there are multiple instances of references to animations from other vehicles, like the MH6 bench sitting pose, or the HMMWV gunner dead pose, or the Stryker dead pose... unfortunately, we need those as well, so we copy them over. The files are relatively small, so usually it's not a big concern if they aren't shared with their respective original vehicles. The MH6 animations will be found in the air directory of your ArmA 2 data release, or, if you checked out the git repository, in //cup-airvehicles/ca/air/data/anim//. After you copied over the files, we need to create //CfgMoves.h// (remember to uncomment it from/add it to the //config.cpp// file). The final result can be found in the sample data released with this guide. It's also probably a good practice to rename the animations to something specific to the vehicle, to avoid clashes with other vehicles. Take note of the added entries //leftHandIKCurve// and //rightHandIKCurve//. Those are important later and enable the driver and gunner to keep their hands on the wheel/the gun. More on that later. In any case, once you're done, repack via pboProject, and retry in game. ====== Turrets: Adding the gunner ====== So we got the passengers working now, but we still need to deal with the gunner position. This is handled by //class Turret//. For a discussion of //class Turret//, see the biki. We'll only discuss the parts that are in need of adaption for ArmA 3. Copy the original turret description into the //CfgVehicles.h//, into the (up to now) empty //CUP_Datsun_PK_Base class//. Several things need changing. The optics model needs to be either copied over (if the optics are specific to the vehicle), or a default ArmA 3 optics is used. In this case, the optics is the empty model, so we replace it with the ArmA 3 empty model at //\a3\weapons_f\Reticle\optics_empty//. The gunner actions need to be renamed to our own actions, //CUP_Datsun_Gunner01//. Finally, we need to adapt the weapon. This might be very complex, or simple. Most of the time, chances are the weapon already exists in the CUP dataset, in which case it's simply replaced with the CUP weapon equivalent (plus the ammo, of course). In other instances, you might need to create the weapon first. The latter case is covered elsewhere, and luckily, we already have a vehicle PKT. Also, for correct animation, we also need to copy over the AnimSources from the original config file. We also need to make sure that the gunner can look down the sights of the gun. This is achieved with the config entry //memoryPointGunnerOptics//. In our case, it's "eye", so add //memoryPointGunnerOptics = "eye";// to the turrent's class entry. In some cases, aslo gunBeg and gunEnd must be set to the gun's begin and end memory points (to tell the engine, where the fire from this gun is coming from). To have the gunner keep his hands on the gun, we add two additional entries: gunnerLeftHandAnimName = "otochlaven"; gunnerRightHandAnimName = "otochlaven"; This ensures that the hands always stay in the same position relative to the named selection. **Note:** All the memory points for the gun, be it begin and end, views, effects, must be part of the main gun's selection (otochlaven in most cases). Repack and test. ====== Turret, take 2: Variable muzzle flash ====== We're now moving on to our very first ArmA 3 specific feature: Currently, if you fire, the muzzle flash is static. We want it to be variable, like in ArmA 3 vehicles. This requires a slight adaption in both //model.cfg// and //config.cpp// (resp. //CfgVehicles.h//). Let's deal with //model.cfg// first. First of all, the muzzle flash must be a named selection in the skeleton, so add "//zasleh//" to the sections. It is also necessary to define it as a bone, so add //"zasleh"//, //"OtocHlaven_Shake"// to the skeleton. Note that the selection name for the muzzle flash as well as the parent bone will depend on the model. We add this to the CUP_datsun_pk's Animation class: class zaslehROT_PKT { type="rotationZ"; source="muzzle_rot_PKT"; sourceAddress="mirror"; selection="zasleh"; axis=""; centerFirstVertex=true; minValue=0; maxValue=4; angle0="rad 0"; angle1="rad 360"; memory = 1; }; This represents a pretty standard rotation around the Z axis. The interesting part is the //source=// line: "//muzzle_rot_PKT//". We need to define this source in the //config.cpp// //AnimationSources class//, like this: class muzzle_rot_PKT { source = "ammorandom"; weapon = "CUP_PKT_W"; }; The source ammorandom is a random value depending on the current ammo count, and the weapon line defines the weapon to use. So //muzzle_rot_PKT// is a random value for each shot fired, causing a random rotation of the muzzle flash. ====== Turret take 3: Adding fire from vehicle positions ====== Fire-from-Vehicle positions are actually very similar to normal turret definitions. They are derived from //class CargoTurret//. The Datsun has two positions suitable for that purpose, namely the two read passengers that sit on the end of the truck bed. We add the two //CargoTurret_01// and //CargoTurret_02// entries to the class Turret of the baseclass and reference them in derived classes. For the details, check the included sample data (search for //CargoTurret//). One problem, though, is the fact that the normal cargo poses do not work for this purpose. In essence, you will need actions that allow using pistols, binoculars and other items. Creating those is beyond the scope of this short document. Luckily, there is a FFV pose that is available which fits our case: The littlebird bench pose, "//passenger_bench_1//". The only thing we need to do is adjust the positions of the proxies so the animation will fit. **Note: It seems that every //CargoTurret// must have it's own set of entry points (//memoryPointsGetInGunner//, //memoryPointsGetInGunnerDir//), so we have to duplicate the existing ones and rename them (see //cfgVehicles.h//). The same points can be used for other turrets still, though.** = Turret take 4: Fixing bullet case ejection and gun clouds = You might notice that the empty cases drop out of the center of the gun, not where they are supposed to be. To accomplish that, we need to make our first modification to the model itself. Checking the //CUP_PKT_W// (weapon class name may vary) definition in //VehicleWeapons//, you will notice this at the end of the weapon definition: class GunParticles { class FirstEffect { effectName = "MachineGun2"; positionName = "machinegun"; directionName = "machinegun_dir"; }; class SecondEffect { positionName = "machinegun_eject_pos"; directionName = "machinegun_eject_dir"; effectName = "MachineGunCartridge1"; }; }; The mentioned position and direction names are memory points. The appropriate effect is created at the positionName in the direction of directionName. In our example, the ejection port memory points already exist, so we just need to create two vertex groups in blender, name them //machinegun_ejcet_pos// and //machinegun_eject_dir// and add the appropriate points (//nabojnicestart// and //nabojnicesend//, respectively). The same applies to the first effect: Create the vertex groups machinegun and //machinegun_dir//, and add the memory points (//usti hlavne// and //konec hlavne//). As always, repack and test. ====== Making the model behave: Geometry LOD ====== ArmA 3 models have the weights of individual components set to zero, and artificial "weight" components added. Basically, you add four weights in the front, rear, left and right of the car to determine the weight and the center of mass. To prepare, remove the weight from all components except the wheels. Then, add cubes to the model and place each into their own selection (name them //ComponentXX//, with XX being continuous numbers). ====== The scary part: PhysX ====== PhysX in itself isn't that much of a problem. It requires a lot of tweaking, though. The first thing we need to do is create a PhysX LOD. This is almost always achievable by copying and modifying the Geometry LOD. In Blender, create a copy of the Geometry LOD and move it to a different layer for easier access. Set the LOD type to "Geometry PhysX". Then, remove the wheels. The wheels are later on replaced by the engine. To achieve this, you need to make sure the wheel's boundaries are marked by a memory point. Most ArmA 2 vehicles will already have the wheel's axis defined, namely, there will be a selection called "//wheel_x_y_axis//", with x and y being 1 or t. For each of those, we also have to insert a single memory point selection called "//wheel_x_y_bound//", so we add four vertex groups in the Memory LOD, and call them //wheel_1_1_bound//, //wheel_1_2_bound//, //wheel_2_1_bound//, and //wheel_2_2_bound//. Also, the axis for damper movements are possibly not in, so we need to add them. They are usually called "//posun wheel_x_y//" (posun is czech for "shift"). They consist of two memory points that are aligned along the axis of the damper (see the example model). After exporting the model as P3D, we can look at the PhysX part of //config.cpp//. For testing purposes, we can use the one that comes with the samples. Copy it into the vehicle's folder as //physx.h//, and //#include// it in the base class. In our example, we also had //maxSpeed// and //wheelCircumfence// defined in the main //cfgVehicles.h//. We move them to the physx.h to keep all engine related data together. The whole setup of the PhysX config is beyond what we want to discuss here, but one thing is important to make the car behave correctly: Every wheel has three parameters that are important: //sprungMass//, //springStrength//, and //springDamperRate//. The latter two are computed from the first. //SprungMass// is what the wheel's spring has to carry in terms of weight. Basically, a quarter of the vehicle mass. Our Datsun has a weight of 1080 with wheels, so a quarter would be 270. //springStrength// is the mass times 25, and //springDamperRate// is 0.4 * 2 * sqrt(springStrength*sprunMass), so they are 6750 and 1080, respectively. If you encounter problems, like, wheels penetrating the floor, or the front wheels losing contact to the surface when accelerating, check those three values for each wheel first. The sum of the sprungMass must be the weight of the car, even if it's not evenly distributed. The other values are computed from sprungMass, and if they are not evenly distributed, you need to compute it again for each wheel. PhysX is a scary subject, and tweaking all the parameters is not easy and requires, first and foremost, experience and/or patience. ===== Lights: Adding reflectors, light cones and more ===== ArmA 2 vehicles have rather simplistics lights: Most of the time, it's a polygon or a few polygons in front of the actual lights containing a flare texture that is made visible when the lights are turned on. In ArmA 3, this has been replaced by several additional features: * Automatically placed lens flares * Light cones that simulate light reflecting off atmospheric particles * Emissive materials * Headlights, rear lights, break lights, reverse lights, and daylight strips * Hitpoints All of these features need some work. We discuss those in detail in the following sections. ===== Lights, take 1: Reflectors ===== The automatically placed lens flares and dynamic lights are rather simple to add. But first, we must actually remove something, namely, the polygons that previously made up the lens flares. To do this, go through all visible LODs (1, 2, 3, 4, etc, as well as view cargo/pilot/gunner), and remove the flare polygons... these are usually quite visible in front of lights like headlights, searchlights or any other lights on the model (Note: This does NOT apply to position lights on planes). The associated selections are usually called //P svetlo// and //L svetlo//. You might also want to delete those selections, since we are going to give them translated names. These names have to be added to the //model.cfg// as well, so add the appropriate names to the sections list of the //CUP_datsun_PK// class in //model.cfg//. For reference, the list should look like this: sections[]= { "camo", "zbytek", "zasleh", "Light_L2", "Light_R2", "brzdove svetlo", "reverse_light", "daylights" }; Next up, we need to put in the appropriate memory points. Those are referenced in class Reflectors in the config file, and we're free to chose the name. For the headlights, we'll go with //LightCarHead//, adding a letter for left (L) or right (R) and a number. The Datsun has two pairs of headlights as well as two halogen lights on the roll bar. So, we will end up with memory points //LightCarHeadL01/02/03// and //LightCarHeadR01/02/03//, as well as their directions (with an added "//_end//"). If the above isn't clear enough, check the included //cfgVehicles.h//, //class Reflectors//. So go ahead and add these selections and memory points to the memory LOD. Check the sample model if you are lost. ===== Lights, take 2: Light cones ===== Light cones are proxies that are switched on and off with the lights. Adding those is easy: Just add an appropriate proxy to each LOD you want them to be visible in, and wrap the proxy in a selection (//Light_L// or //Light_R//) accordingly. For the model referenced by the proxy, select //\a3\data_f\VolumeLightCar//. In Blender, you can create the proxy in one LOD, and copy it over to all the LODs that you need it in via the Blender Toolbox proxy tools. Note that to be able to individually destroy the headlights and the roll bar lights later, we place the roll bar light proxies into their own selections, respectively //Light_L2// and //Light_R2//. ===== Lights, take 3: Emissive materials and additional lights ===== Tail lights and other lights that do not cast real light or have generated lens flares are generated differently. They are not part of the //config.cpp//, but rather selections in the model that are hidden and shown depending on different factors. For tail and brake lights, a special red emmissive material is used, either with a red color texture, or you can even use the body texture of the car if you can re-use polygons from the car model itself. Note that this will require some minor modeling experience. What you basically do is to use polygons shaped like the actual light source but offset a tiny bit in front of the actual light, and give it a special material. In fact, this is similar to what the original ArmA 2 models did. We'll walk through one example of "re-using" and one example of creating a new light. First, let's start with the front light, re-using the existing polygons. Note, to have full access to the headlights, try to hide the bars and grilles in front of them. Select all the polygons that make up the glass parts of the two left headlights. Press Shift+D to duplicate, and immediately click right.. then move the duplicate a tiny bit forward so it does not intersect the old polygons. Add those polygons to the //Light_L// selection resp. the //Light_L2// selection for the roll bar light, and, **VERY IMPORTANT**, make sure they are not in any other selection. Duplicate the material the polygons already have, and assign the new one to the separated polygons. Scroll down to the Arma properties of the material, and select //P:\a3\data_f\lights\car_headlight_emit.rvmat// as it's RV material file. Now, repeat the process for the left roll bar light, and then for the right side (using selection //Light_R// and //Light_R2//, of course). You will need to copy the polygons you created in such way into the other LODs as well, but for practical purposes, it's enough to skip higher LODs (beyond 3). It won't be visible anymore, anyway if this LOD is shown. Also, don't copy them into LODs where they wouldn't be visible, anyway, due to view limitations, like the interior LOD of the car. The second method is similar. Create a plane mesh and scale it accordingly so it fits the light you want to make emissive. If it's a break or tail light, create a new material and set it to a red color and use //P:\a3\data_f\lights\car_breaklight_emit.rvmat// as the materials' RV material file. Don't forget to add the polygons to the appropriate selection (see above). Head and tail lights can be done like described above. When added to the //Light_L// and //Light_R// selections, they will become visible and invisible depending on the state of the car's lights. But what about break lights, and reverse lights ? These require special config entries. Reverse lights are not directly supported by the engine. Therefore, we simulate them by hiding and showing the lights depending on the gear: Negative gears make the reverse light appear, while positive or neutral gear makes them hidden (The //model.cfg// already has an appropriate entry). Break lights are supported, and the name of the selection must be mentioned in the //config.cpp//. To do this, it would be necessary to add //selectionBrakeLights = "break_light";// to the //cfgVehicles.h//. However, this does not seem to work, so the selection must be named "//brzdove svetlo//". ===== Light, take 4: Associated hitpoints ===== Even though the Car guideline on the BIKI says that hit points are generated automatically, this isn't the case. You must still place them manually. Rename //L svetlo// and //P svetlo// to //Light_L// and //Light_R//, respecitvely. We also want the top lights (on the roll bar) to be destructible independently from the main lights. So, for those two, we use separate hitpoints named //Light_L2// and //Light_R2//. We need to place those in the hitpoints LOD in front of the appropriate lights. Also, to be able to actually hit the hitpoints, we need to add some geometry to the Fire Geometry LOD representing the light casing. Two tapered cubes should do the trick. Add each one individually to a new selection named //ComponentXX// and //ComponentYY//, with XX and YY being the next two numbers in sequence. ===== Now for something easy: Adding sling loading ===== Sling loading is easily added: Just add four memory points and mention them in the config. The memory points are used for connecting ropes to the vehicle (Note: Adding sling loading capability to helicopters is something different, we're going to add another tutorial later dealing with air vehicles). So, add four memory points called //SlingLoadCargo01-04//, preferably to some point that seems logical (like, the roll bar, front grating, etc), and mention them in the config file: slingLoadCargoMemoryPoints[] = { "SlingLoadCargo1", "SlingLoadCargo2", "SlingLoadCargo3", "SlingLoadCargo4" }; ===== Keeping the hands on the wheel ===== Having the driver keep his hands on the wheel is pretty easy and achieved in a similar way to keeping the hand on the gun. You need to name a bone that the hands move relative to. In cars, this is usually the drivewheel selection: driverLeftHandAnimName = "drivewheel"; driverRightHandAnimName = "drivewheel"; The problem in our case is that the animation looks rather awkward due to the position of the hands. A better solution in this case would be to replace the driver animation with a default driver anim from ArmA 3. This, however, requires some adaption. Mostly because the driver proxy is not in the correct position. You will need to move it so it fits. You might want to try different versions (//driver_low01//, //driver_mid01//, //driver_high01//), and if none of them works, adjust the proxy. **Tip:** if you want to try different actions quickly, load Object Builder, select the Cargo view, then click on the driver's proxy and click "Rename"... you can pop up a file requester from there and try the different versions found in //P:\a3\data_f\proxies//, quickly checking the fit in Buldozer. For our example, the //driver_high01// fits quite well, so change the //driverAction// in //cfgVehicles.h// accordingly. ===== Some special effects: Exhaust effects ===== Every car has one or more exhaust pipes, which spew out black, toxic vapor when the car is burning fuel. In ArmA 3, the effect is handled by class Exhausts in //config.cpp//: class Exhausts { class Exhaust1 { position = "exhaust"; direction = "exhaust_dir"; effect = "ExhaustsEffect" ;} ;}; The class defines position and direction of exhaust effects. Both "//exhaust//" and "//exhaust_dir//" are memory points. If the car has more than one, add more effects, like: class Exhausts { class Exhaust1 { position = "exhaust"; direction = "exhaust_dir"; effect = "ExhaustsEffect"; }; class Exhaust2 { position = "exhaust2"; direction = "exhaust2_dir"; effect = "ExhaustsEffect"; }; }; The Datsun has one exhaust, so the first version is sufficient. The appropriate memory points are already in the model, but since //Car_f// has most czech names translated, you need to rename the memory points "//vyfuk konec//" to "//exhaust_dir//" and "//vyfuk start//" to exhaust (or enter the appropriate czech names instead of the translated names in //config.cpp// above, but we advice to use English names). ===== More special effects: Track markers ===== Track markers used to leave tire marks on the ground. For this purpose, you need to define two memory points for each tire, one on each side of the tire. In other words, 8 memory points are used and have to be named in the config file, like this: memoryPointTrackFLL = "tyreTrack_1_1l";// Originally stopa PLL memoryPointTrackFLR = "tyreTrack_1_1r";// Originally stopa PLP memoryPointTrackBLL = "tyreTrack_1_2l";// Originally stopa ZLL memoryPointTrackBLR = "tyreTrack_1_2r";// Originally stopa ZLP memoryPointTrackFRL = "tyreTrack_2_1l";// Originally stopa PPL memoryPointTrackFRR = "tyreTrack_2_1r";// Originally stopa PPP memoryPointTrackBRL = "tyreTrack_2_2l";// Originally stopa ZPL memoryPointTrackBRR = "tyreTrack_2_2r";// Originally stopa ZPP Like the car exhaust points, these are already in the model, just with a czech name, "//stopa XXX//" with XXX being a combination of letters. If they aren't present, add them according to their names (//tyreTrack_1_1l// and //tyreTrack_1_1r// are obviously left and right of //wheel_1_1// etc). ===== Even more special effects: Dust markers ===== Dust markers might or might not be in the model. dustFrontLeftPos = "dustFrontLeft"; dustFrontRightPos = "dustFrontRight"; dustBackLeftPos = "dustBackLeft"; dustBackRightPos = "dustBackRight"; When driving forward, dust particles are generated at the front positions, and when driving backwards, dust is generated at the back positions. This leads to the rather unintuitive placement of the "Front" memory points at the rear of the rear wheels, and the "Back" memory points at the front of the front wheels. ===== Reflections and more: Picture-in-Picture ===== Mirrors are an exiting new feature for ArmA 3, and require some modeling work to set up the appropriate mirror surfaces. Don't be alarmed, though, all you need to do is duplicate polygons, much like you already did for the lights. For performance reasons, ArmA 3's mirrors are only visible from within the vehicle, not from third person view. For that reason, the mentioned modifications will only be carried out on inside views. These might include View – Cargo, View – Pilot, or View – Gunner. Note that for this specific case (our Datsun) we are only doing rear view mirrors. Other vehicles might require different kinds of PIP views. For example, the BTR-90 has several internal periscopes that are PIP surfaces, allowing the turned-in driver and commander to see the outside world. So in the Datsun case, we have three mirrors, one inside, and two outside. They will only be visible in View – Cargo. First of all, we need to "cut out" the polygons that make up the actual reflecting surface. Select the appropriate polygons, and press CTRL+D to duplicate, click right immediately and use the handles to pull out the surface a tiny bit. **Important: The mirror surfaces were most likely part of other selections. Most notably, in this case, the "camo" selection which is one of the hidden selections and thus, any texture assigned to any polygon in that selection might get overwritten by the hidden selection. Therefore, make sure that the mirror surfaces are removed from other selections, at least from those that are hidden selections.** PIP surfaces use special procedural textures. The texture will be replaced with the PIP view. As with any texture, the UV coordinates determine which part of the texture is seen on the polygons. PIP views produce a square texture with U/V coordinates from 0 to 1. To make sure we see the PIP view on the mirror, select all it's vertices, switch Blender to UV/Image Editor, and rotate and scale the vertices so that the mirror surface has maximum coverage. Repeat that for all mirrors. One note: They are mirrors. The view on the texture surface is a straight view and therefore, it's like a camera, not a mirror. To make them mirrors, you need to scale all polygons by -1 on the x-Axis only (in the UV/Image Editor view, of course, not on the 3D model). Next, create the actual material. In materials tab, click on '+' to add a new material, name it "//Rendertarget 0//", then scroll down to the Arma part. Select "Custom", and enter //"#(argb,256,512,1)r2t(rendertarget0,1.0)"// next to "Custom Procedural Texture". Repeat the step for Rendertarget 1 and Rendertarget 2, setting them to //"#(argb,256,512,1)r2t(rendertarget1,1.0)"// and //"#(argb,256,512,1)r2t(rendertarget2,1.0)"//, respectively. Back in 3D view, assign the textures RenderTarget 0/1/2 to the polygons of the left mirror, right mirror and center mirror, respectively. We need to define position and direction of the PIP's virtual observers. We use //pip0_pos/pip0_dir//, //pip1_pos/pip1//_dir and //pip2_pos/pip2//_dir for rendertargets 0, 1 and 2 respectively. The appropriate entries must be added to //cfgVehicles.h//. The final result can be seen in //cfgVehicles.h// and the p3d file included with the sample data. Check the View – Cargo LOD as well as the memory points. ===== Doing some damage: Hit points ===== In essence, hit points work in the same way as they did in ArmA 2. However, ArmA 3 tends to put them closer together to form a tighter mesh. Additionally, some internal structures like the engine and fuel tank have quite a number of hit points. A new feature in ArmA 3 is the ability to set the radius for the hitpoints, allowing them to be packed tighter to gain more control over the form used. The easiest way of creating the dense hitpoint mesh for the engine is to copy the hitpoints from the sample model. Otherwise, create a grid (say, 7 x 5 vertices), remove all the edges and faces, and duplicate it some 5 times at even intervals. Add them to the selection "engine" and place them under the hood of the car. Likewise, create a reasonably size chunk of points for the "fueltank". See the sample model for clarification.