====== ArmA 3 bis Car's Config Guidelines ====== [[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]] ====== Additional Functionality Compared to A2/OA ====== * PhysX 3 integration * IK for hands/legs * Picture in Picture - Render to texture * Random visual variants (textures, accessories, doors) * Floating and sinking * Reflectors, markerlights and beacons ====== Model Requirements (P3D) ====== **A new PhysX lod** There needs to be a lod (4e13) consisting of convex components as simple as possible, some 60 faces shall be sufficient for most cars Current public Oxygen version doesn't support showing correct name of this lod and displays only Geometry instead. Don't be afraid of having two geometries, it's going to be fixed with new tools. Just the main body of car should be in this lod, wheels are added by engine later {{ https://pmc.editing.wiki/images/bis-cars-config-guidelines-physx-lod.jpg }} **Memory lod** There should be an axis for each wheel named wheel_X_Y_axis (X is position of wheel from front, Y is 1 for left and 2 for right), the name is defined in selected wheel as center There should be a point at the edge of each wheel named wheel_X_Y_bound which is used to determine wheel radius (distance from wheel axis is used for this) - there is no other need than placing the point at the edge, even memory points for tracks could be used for this, the name is defined in selected wheel as **boundary** {{ https://pmc.editing.wiki/images/bis-cars-config-guidelines-physx-bound.jpg }} Mirrors and screens should have their camera position defined in pipX_pos and direction in pipX_dir - parameters pointPosition and pointDirection in class RenderTargets Reflectors should have their position defined in LightCarHeadYXX (Y is a side - R/L, XX is a number) and direction defined in LightCarHeadYXX_end Mirrors and screens should have RTT texture: #(argb,256,512,1)r2t(rendertargetX,1.0) - where X in rendertarget should be a number Randomly generated accessories should have their selections independent on all other selections (mainly the main body and all the glass selections), glass as a part of hide-able accessory should be handled as two separate selections Beacons and markerlights should have their material set to emit light Spare wheel should have defined selections for it, texture underneath and correct hitpoints like a normal wheel Man-held turrets shouldn't be hidden when destroying them without destroying the whole vehicle - IK issues would crash the game ====== Model Config Changes (model.cfg) ====== Only the dampers are affected by the changes, best way to set them is to place an axis with the length of moveable part alongside the damper and set offsets to +-0.5 model.cfg: class Wheel_1_1_Damper { type = "translation"; source = "damper"; selection = "wheel_1_1_damper_land"; axis = "posun wheel_1_1"; animPeriod = 1; minValue = "0"; maxValue = "1"; offset0 = "0.5"; offset1 = "-0.5"; memory = 1; }; Sections for hiddenSelectios[] should be set in model.cfg ====== New config parameters (config.cpp) ====== ===== Basic parameters ===== Following parameters are defined in vehicle class. * : string * : (required) * simulation = "carx"; * : float * : 0.0 * dampersBumpCoef = 0.3; ===== Differential parameters ===== * : string; accepable values: "all_open", "all_limited", "front_open", "front_limited", "rear_open", "rear_limited" * : "all_limited" * differentialType = "all_limited"; * : float * : 0.5 * frontRearSplit = 0.5 * : float * : 1.3 * frontBias = 1.3; * : float * : 1.3 * rearBias = 1.3 * : float * : 1.3 * centreBias = 1.3 * : float * : 10.0 * clutchStrength = 10.0; * : float * : 0.01 * switchTime = 1.01; ===== Engine parameters ===== * : float * : (required) * enginePower = 600; * : float * : 600 which is cca 6000 rounds per minute. * maxOmega = 600; * : float * : value calculated from enginePower according to http://en.wikipedia.org/wiki/Horsepower#Relationship_with_torque * peakTorque = 600; * : float, float, float * : 0.08, 2.0, 0.35 * dampingRateFullThrottle = 0.08; * dampingRateZeroThrottleClutchEngaged = 2.0; * dampingRateZeroThrottleClutchDisengaged = 0.35; * : Array[i][2] where i = number of samples, maximum 8; * : {{0.0, 0.8}, {0.33, 1.0}, {1.0, 0.8}} * torqueCurve[] = {{0.0, 0.8}, {0.33, 1.0}, {1.0, 0.8}}; ===== Wheel Parameters ===== This parameters relates to each wheel. In the vehicle class, there has to be subclass called Wheels, which contains subclass for every wheel the vehicle has. These are the parameters that could be defined in that subclasses. ===== General Parameters ===== * : string * : "" * boneName = "wheel_1_1"; * : bool * : (required) * steering = true; * : string * : "right" * side = "left"; ===== Wheel PX Parameters ===== * : memory point * : (required) * center = "wheel_1_1_axis"; * : memory point * : (required) * boundary = "wheel_1_1_bound"; * : float * : 0.3*(raidus of the wheel) * width = "0.2"; * : float * : 10.0 * mass = 150; * : float * : 0.5 * WheelMass * WheelRadius * WheelRadius * MOI = 40; * : float * : 0.1 * 'dampingRate = 0.1; * : float * : 2500 * maxBrakeTorque = 7500; * : float * : 2*maxBrakeTorque * maxHandBrakeTorque = 0 ===== Wheel Simulation Parameters ===== * : Array[3] * : {0, -1, 0} * suspTravelDirection[] = {0, -1, 0}; * : memory point * : center * suspForceAppPointOffset = "wheel_1_1_axis"; * : memory point * : suspForceAppPointOffset * tireForceAppPointOffset = "wheel_1_1_axis"; ===== Suspension Parameters ===== * : float * : 0.15 * maxCompression = 0.15; * mMaxDroop = 0.15; * : float * : vehicleMass/numberOfWheels * sprungMass = 2066; * : float * : sprungMass*5,0*5,0 * springStrength = 51653; * : float * : 0,4*2*sqrt(springStrength*sprungMass) * springDamperRate = 8264; ===== Tire Parameters ===== * : float * : 10000 * longitudinalStiffnessPerUnitGravity = 10000; * : float, float * : 25, 180 * latStiffX = 25; * latStiffY = 180; * : Array[3][2] * : {{0, 1}, {0.5, 1}, {1,1}} * frictionVsSlipGraph[] = {{0, 1}, {0.5, 1}, {1,1}}; ===== Floating and sinking ===== WaterLeakiness should be amount of water in liters that goes into selected object per second. This is set to zero by engine for all vehicles with simulation of a ship or having canFloat = 1 (unless they are toppled of destroyed, then config value takes precedence). WaterLeakiness = 10; seems to be a good value to start with for all kinds of vehicles no matter the size (which is a bit spooky, but it works). ===== PhysX 3 integration ===== **WheelMask** **thrustDelay** is time in second in which thrust goes from 0 to 1 when standing still (doesn't affect driving car during change of gears), 0.2 seems to be a reasonable value. You may want to tweak this to higher values if wheels slide during initial acceleration. **brakeIdleSpeed** is speed in m/s under which the brakes are automatically applied to the vehicle. This speed should be reasonably low, higher value would mean strange breaking of slow cars, too low value would cause inability to stop the car. **idleRpm** sets the idle RPM of engine. Primary use is for sound engine **redRpm** sets the maximum for engine RPM, should be according to maxOmega (see later) **Anti-roll bars** Anti-roll bars is the system in vehicle that should prevent it to do a barrel-roll during sharper turns. Using ARB enables us to make center of mass realistically high and cause cars to roll down the steep slopes if placed sideways to the slope. It works the same way as the real ones - system computes difference of applied weight to wheels in pair and tries to compensate difference by applying opposite forces. antiRollbarForceCoef is a coefficient of applied force, could be taken as strength of the system. Setting this value to zero disables ARB (and all next values), which is good for civilian vehicles, higher values reduce not only the risk of rolling, but effects of suspension. antiRollbarForceLimit is the highest strength of ARB applied to vehicle. We may want to roll the car at certain situations (full van taking sharp hand-brake turn at high speed), tunning without diag mode is almost impossible because we are not able to imagine forces needed (values are rather low, 2 should be high enough for most of vehicles) antiRollbarSpeedMin and antiRollbarSpeedMax are limits of applied force coefficient. Coefficient is 0 at speeds lower than antiRollbarSpeedMin, interpolates to antiRollbarForceCoef at antiRollbarSpeedMax and is set to antiRollbarForceCoef for any higher speeds. This allows cars to drive on steep slopes using their radial speed, falling of the hill once they stop and rolling over at too high speeds (where coefficient doesn't grow and force is limited by the limit). **Complex gearbox** All PhysX 3 vehicles use complex gearbox to give some data to PhysX gearbox Complex gearbox settings is inside class complexGearbox which is a subclass of vehicle class GearboxRatios[] is an array of gear names and gear ratios starting with reverse gear (with negative ratios), neutral gear (which should have zero ratio) and forward ratio (eg: {"R1",-3.231,"N",0,"D1",2.462,"D2",1.870,"D3",1.241,"D4",0.970,"D5",0.711};). Gear names are not used in retail version, they are just for epevehicle diagnostics TransmissionRatios[] is an array of transmission ratios in the same format as gearboxRatios. Most of cars have only one transmission ratio, some heavy trucks may have two. The final ratio of engine is gearboxRatio * TransmissionRatio, that means transmissionRatios shouldn't be multiplicates of each other and gearbox ratios to prevent the same final ratio for two different gears. gearBoxMode is set to full-auto by engine moveOffGear defines what gear an automatic or semi-automatic gearbox will move off from stationary in. 1 by default. driveString, neutralString and reverseString define displayed strings for driving forward, neutral and backward. config.cpp: class complexGearbox { GearboxRatios[] = { "R1", -3.231, "N", 0, "D1", 2.462, "D2", 1.870, "D3", 1.241, "D4", 0.970, "D5", 0.711 }; TransmissionRatios[] = {"High",4.111}; // Optional: defines transmission ratios (for example, High and Low range as commonly found in offroad vehicles) moveOffGear = 1; // defines what gear an automatic or semi-automatic gearbox will move off from stationary in. 1 by default. driveString = "D"; // string to display in the HUD for forward gears. neutralString = "N"; // string to display in the HUD for neutral gear. reverseString = "R"; // string to display in the HUD for reverse gears. }; **Gearbox parameters** Some gearbox parameters are defined outside of class complexGearbox, they are mainly to setup automatic gearbox changeGearMinEffectivity[] Value of minimal gear effectivity to hold current gear. If there is better gear and effectivity is below this value then change gear. It is an array of effectivities ordered by gears in complex gearbox. Neutral should have rather low effectivity (0.15 seems to be a good value), drive gears should have rather high value (around 0.95) to prevent switching gears too often switchTime The switch time describes how long it takes (in seconds) for a gear change to be completed. RPM interpolate to optimal value for the new gear at current speed during the changing of gears. The time should be rather low, around 0.3 s, to keep the momentum of the car. latency is the minimum time (in seconds) that must pass between each gear change that is initiated by the autobox. This should be set to value higher than switchTime. Setting this time too low makes some issues with changing gears - the car slows down a lot **Different amount of torque** coefficients for different speeds of Slow, Forward and Fast are now configurable slowSpeedForwardCoef is set to 0.3 by default normalSpeedForwardCoef is set to 0.85 by default default speed coefficient for fast movement is 1 meaning that full throttle is applied and maximal speed is maxSpeed of the vehicle (it is going to apply less throttle upon reaching the limit) ===== IK for hands and legs ===== It's not Inverse Kinematics in fact, but as close to it as possible. A soldier should have IK defined for hands and legs by default Each vehicle pose using IK should have leftHandIKCurve[] and rightHandIKCurve[] set to 1 Driver should have driverLeftHandAnimName and driverRightHandAnimName defined as drive wheel bone of the vehicle (drivewheel by default) Gunner should have gunnerLeftHandAnimName and gunnerRightHandAnimName defined on handles of the gun, or shaking bone of the weapon shall be sufficient (usually something like otocHlaven_shake) Double check names of bones if the game crashes upon loading this vehicle and call stack points to IK. Wrong definition causes CTD all the time and removing the bone causes the same (eg. by hiding it). ===== Picture in Picture for screens and mirrors ===== All sources for textures to be rendered on are defined in class RenderTargets which is a subclass of vehicle class Each source is a separate subclass with unique name parameter renderTarget defines which texture shall the source be mapped at (only the rendertargetX part is used) class CameraView1 is a subclass of this source and contains all the parameters for rendered scene pointPosition and pointDirection should be respective memory points in model renderQuality is in range from 0 to 2 and defines quality of rendering for said source renderVisionMode defines the vision mode - 0 = HDR, 1 = NightVision, 2 = ThermalVision, 3 = Color, 4 = Mirror fov defines field of view of this source config.cpp: class RenderTargets { class LeftMirror { renderTarget = "rendertarget0"; class CameraView1 { pointPosition = "PIP0_pos"; pointDirection = "PIP0_dir"; renderQuality = 2; renderVisionMode = 0; fov = 0.7; }; }; }; ===== Random visual variants ===== Randomization of variants is done by script ran upon start of mission via init event handler The car should inherit class EventHandlers: EventHandlers init event handler should be changed to something like this: init = "(_this select 0) execVM ""\pathToCar\scripts\scriptName.sqf"""; Don't forget to hide all the added accessories upon destruction of vehicle, they are usually in proxies, this is handled by killed event handler: killed = "_this call (uinamespace getvariable 'BIS_fnc_effectKilled'); _this select 0 animate [""RandomAnimation"", 0]; **Random variants script** All random settings should be done on server side to prevent different car looks for different users script.sqf: if (isLocal) then { _rnd1 = floor random Y; _this setVariable ["BIS_randomSeed1", _rnd1, TRUE]; _this animate ["RandomAnimation", X]; }; Y stands for the number of random variants Even all the animations should be handled server-side to ease clients, RandomAnimation shall be replaced by any animation needed to be randomly chosen, X stands for animation phase script.sqf: waitUntil { !(isNil {_this getVariable "BIS_randomSeed1"}) }; _randomSeed1 = _this getVariable "BIS_randomSeed1"; Random textures shall be taken with this statement: script.sqf: _this setObjectTexture [0, ["\pathToCar\Data\variant_1_co.paa", ...,"\\pathToCar\Data\variant_Y_co.paa"] select _randomSeed1]; ===== Reflectors, markerlights and beacons ===== **Reflectors** Reflectors need to be defined in class Reflectors Default cars should have two reflectors defined as separate subclasses inside class Reflectors. These two classes should differ only in position, direction, hitpoint and selection. Position and direction are self-descriptive, they use memory points in mode, hitpoint is the name of selection in hitpoint lod in model, selection is a visual selection in resolution lods. Most of reflectors should have useFlare set to 1, they are bright enough to have a flare. Size of this flare is defined by flareSize, value should be rather low, around 0.1 seems to be good for start. class Attenuation inside each reflector subclass defines behavior of light from distance. Attenuation is combination of constant, linear and quadratic coefficient, start is a distance from position where attenuation starts to work (the light is at it's full strength if distance is lower than start). aggregateReflectors[] outside of Reflectors class is used to ease computing of too many light sources and combines light together. Both reflectors should be aggregated for a default car but feel free to experiment. Just run some FPS test after testing non-standard settings. **Markerlights** Markerlights are purely model side based on assigned emissive materials **Beacons** Beacons consist of two parts on model side - emissive one and unlit one. The emissive one is hidden by default by an user controller and periodically hidden by time controller in model.cfg Config contains only user actions to turn beacons off/on by hiding/unhiding them, this is inside class UserActions: UserActions There should be two actions per beacons set - one to turn them off and other to turn them on, each as a subclass of UserActions config.cpp: class UserActions: UserActions { class beacons_start { userActionID = 50; displayName = "Beacons start"; displayNameDefault = ""; position = "mph_axis"; radius = 1.8; animPeriod = 2; onlyForplayer = false; condition = "this animationPhase ""BeaconsStart"" < 0.5 AND Alive(this) AND driver this == player"; statement = "this animate [""BeaconsStart"",1];"; }; class beacons_stop: beacons_start { userActionID = 51; displayName = "Beacons stop"; condition = "this animationPhase ""BeaconsStart"" > 0.5 AND Alive(this) AND driver this == player"; statement = "this animate [""BeaconsStart"",0];"; }; }; ===== Basic config hints ===== **Diagnostics** Drive around as much as possible, preferably using real islands. Use Stratis airstrip for acceleration, gear change and sinking of vehicle purposes Path from Jay Cowe to Airstation Mike-26 on Stratis is great to test uphill performance of the car and AI driving skills Whole Chernarus is excellent playground to test vehicles **Suspension** Easier way to set up suspension is to have center of mass centered according to wheels. Non-centered center of mass is more interesting for driving performance, just be sure to make center of mass centered at least in left-to-right axis. Each wheel could have different suspension parameters but try to keep them the same for wheel pairs. You may try to use ARB if the car sways a lot sideways during turns. This causes lesser side sway but doesn't reduce bumping of suspension when accelerating and breaking. **Gearbox** Real gearbox ratios have extremely good results for higher speeds and are realistic for lower speeds. But it is better to use some lower values for lower gears to improve acceleration Look out for too big steps between gear ratios, this may prove to be problematic with steep torqueCurve - engine would change gear later than expected and sound would go fubar dampingRateZeroThrottleClutchEngaged and dampingRateZeroThrottleClutchDisengaged could be the same, this works really well for FWD cars - engine would slow them down way too much and lock the wheels when only directional arrow is pressed