Howto:Add submodels

From FlightGear wiki
Jump to navigation Jump to search
B-29s dropping their load.

Submodels are the means in FlightGear whereby we can represent anything which is dropped, fired, or launched from an aircraft or indeed any model – the possibilies are endless. Some examples which can be found in FlightGear: guns, flares, bombs, and droptanks.

In general, AI models are instantiated at startup, but submodels, which use only C++ AIBallistic objects, are pre-loaded at startup, but only instantiated when required.

This howto will explain how to add submodels to your model.

Step 1: Create the submodel

First, create the file Models/submodels.xml containing a <submodel> inside a <PropertyList tag>:

<?xml version="1.0" encoding="UTF-8"?>

<PropertyList>

    <submodel>
        <name>M-17.001-submodel</name>
        <model>/Aircraft/b29/Models/M17.xml</model>
        <trigger>/sim/weapons/loadout[1]/bomb[0]/dropped</trigger>

        <repeat>false</repeat>
        <count>1</count>
        <delay>0</delay>

        <speed>0</speed>
        <wind>false</wind>
        <aero-stabilised>true</aero-stabilised>
        <eda>1.42</eda>
        <cd>0.75</cd>
        <weight>500</weight>
        <life>900</life>

        <impact>true</impact>
        <impact-reports>sim/ai/aircraft/impact/bomb</impact-reports>
    </submodel>

</PropertyList>

Measurements (except those in <offsets>, see below) are in Imperial Measure: Feet, Inches, Pounds. This is because the original author(s) were American.

The trigger is a boolean property, which you define, which when "true" causes the submodel to be released/launched. For bombs you want <repeat> to be set to "false", <count> to 1, and <delay> to 0. For bullets you want to set <repeat> to "true", <count> to -1, and <delay> to a number greater than zero. If the weapon system has a limited capacity (limited number of bullets) then you should use Nasal or XML (<autopilot> or <property-rule>) to control whether the submodel should be triggered or not.

Step 2: Define the position and orientation

Second, define the offset of the submodel with respect to the center of the model. For example, the forward left Phalanx CIWS of the CVN-70 supercarrier uses:

    <submodel>
        ...

        <offsets>
            <x-m>-121.2666</x-m>
            <y-m>-21.1147</y-m>
            <z-m>16.8345</z-m>
            <heading-deg>
                <property>/carrier/phalanx/output/forward-left/yaw-deg</property>
                <offset>-90.0</offset>
            </heading-deg>
            <pitch-deg>
                <property>/carrier/phalanx/output/forward-left/pitch-deg</property>
            </pitch-deg>
        </offsets>

        ...
    </submodel>

The various tags inside the <offsets> tag support certain tags also seen in <autopilot> files: <property>, <expression>, <value>, <scale>, <offset>, <min>, <max>, <abs>, and <period>.

Tip  Use these to control the submodel's initial position and orientation during runtime. For example, to control the pitch and heading of a Phalanx CIWS (Close-In Weapon System).
Note  The <x-m>, <y-m>, and <z-m> use metric units and have the same coordinate system as the main model. This is unlike the old <x-offset>, <y-offset>, and <z-offset> tags which use imperial units and have the x-axis reversed.

Step 3: Re-use configuration values (optional)

If you want to create multiple instances of the same kind of submodel, for example, multiple guns of the same type, then you should alias tags that you want to re-use:

    <phalanx>
        <model>Aircraft/CVN-70/Models/M61A1/apibullet-tracer.xml</model>
        <speed>3650.0</speed>
        ...
    </phalanx>

    <submodel>
        <name>Phalanx Forward Left M61A1 Bullet Tracer Round</name>
        <trigger>/sim/multiplay/generic/int[3]</trigger>
        <model alias="/phalanx/model"/>
        <speed alias="/phalanx/speed"/>
        ...
    </submodel>

    <submodel>
        <name>Phalanx Forward Right M61A1 Bullet Tracer Round</name>
        <trigger>/sim/multiplay/generic/int[2]</trigger>
        <model alias="/phalanx/model"/>
        <speed alias="/phalanx/speed"/>
        ...
    </submodel>

As you can see, the speed is defined in just one place instead of two. If you ever need to adjust the speed of all the submodels, you only have to adjust one number.

Step 4: Add the submodel to your model

This is very simple. First, add these lines to your model ~-set.xml file within the <sim></sim> tag:

    <submodels>
        <serviceable type="bool">true</serviceable>
        <path>Aircraft/seahawk/Models/seahawk-submodels3.xml</path>
    </submodels>

Where <path> is the path to the file you created at Step 1 above. If you want to add submodels to an AI Object, add the same lines within the <scenario></scenario> tag in the scenario file which instantiates the AI Object.

Step 5: Control the release of the submodel

There is no built-in way of setting/toggling the trigger property so you will need to add some mechanism to do this. A suitable key binding might be:

<key n="10">
    <name>Ctrl-J</name>
    <desc>Jettison Port and Stbd Pylon Stores.</desc>

    <!-- port inner -->
    <binding>
        <command>property-assign</command>
        <property>controls/armament/station[0]/jettison-all</property>
        <value type="bool">1</value>
    </binding>

    <!-- stbd inner -->
    <binding>
        <command>property-assign</command>
        <property>controls/armament/station[1]/jettison-all</property>
        <value type="bool">1</value>
    </binding>
</key>

Step 6: Terminate the submodel

There are 3 ways to terminate your submodel:

  1. Do nothing: the submodel will die when its life expires or its altitude <= -1000, whichever occurs first.
  2. Instantiate a subsquent submodel: <submodel-path> contains the path to the file containing the submodel to be instantiated. Activated if one or more of <collision>, <impact>, or <expiry> are set to true.
  3. Instantiate a static model: for this you will need a Nasal fuction. Example:
var droptanks = func(n) {
    var node = props.globals.getNode(n.getValue(), 1);

    geo.put_model("Aircraft/seahawk/Models/droptank-hot.xml",
        node.getNode("impact/latitude-deg").getValue(),
        node.getNode("impact/longitude-deg").getValue(),
        node.getNode("impact/elevation-m").getValue() + 0.25, # +0.25 to ensure the droptank isn't buried
        node.getNode("impact/heading-deg").getValue(),
    0, 0);
}

setlistener("sim/ai/aircraft/impact/droptank", droptanks);

The path sim/ai/aircraft/impact/droptank is the one you specified in the tag <submodel-path>. Options 2 and 3 are NOT mutually exclusive. Thus you can both instantiate a static model AND instantiate a subsequent submodel. As above, this is activated if one or more of <collision>, <impact>, or <expiry> are set to true.

Notes and configuration

A submodel will create an C++ AIBallistic object which will follow a ballistic path. By default, one submodel will be released when the corresponding trigger is set to "true". The initial conditions define the object's starting point (relative to the user model's current position), and its initial speed and direction (relative to that of the user model aircraft). If you want to release many similar objects with the same initial conditions, then you may use the <repeat>, <delay> and <count> properties to define this.

There is a long list of allowable tags.

<name>
The name of the submodel.
<model>
The path to the visual model. Any model in any location is allowed. All the normal animations are available.
<trigger>
The property which will act as the trigger.
<speed>
Initial speed, in feet/sec, relative to user aircraft.
<repeat>
Set "true" if you want multiple releases of this submodel. Defaults to false.
<delay>
Time, in seconds, between repeated releases.
<count>
Number of submodels available for multiple release.
<buoyancy>
Submodel's upward acceleration (fps) due to buoyancy in air. 32 isneutral (contrails), > 32 exhaust gas, smoke.
<wind>
If true, the Submodel is affected by local wind. Defaults to false. This tag was added to cater for smoke, contrails and the like. The effect of wind on ballistic objects is not well modelled. For bombs, bulllets etc. This is best left at the default setting.
<cd>
The Coeffient of Drag. Varies with submodel shape - 0.295 for a bullet, 0.045 for an airfoil. Enter an appropriate value. Defaults to 0.295.
<eda>
Effective drag area (sq ft). Usually the cross-sectional area of the submodel normal to the airflow.
<weight>
The weight of the submodel (lbs). Defaults to 0.25.
<aero-stabilised>
If true, the submodel aligns with the local airflow. Defaults to true.
<external-force>
If true the submodel is subjected to an external force.
<force-path>
A string describing the property where the magnitude, azimuth and elevation of the external force is to be found. The following child properties are instantiated:
  • force-lb
  • force-azimuth-deg
  • force-elevation-deg

You need to manipulate these properties with some Nasal to apply an external force to the submodel.

<force-stabilised>
If true, the submodel aligns with the external force. Defaults to false. If both this and <aero-stabilised> are true this takes priority.
<no-roll>
If true, the submodel does not bank in turns. Defaults to false.
<collision>
If true, the position of collisions (or hits) with other non-ballistic AI models are reported. Defaults to false.
<impact>
If this is true the position of impact on the terrain is reported. Defaults to false.
<expiry>
If true, the postion of the Submodel when its life expires is reported. Defaults to false. Collision, Impact, and Expiry are handled in that order.
<impact-reports>
A string descibing the location of Collision, Impact, or Expiry position. Defaults to "/ai/models/model-impact".
<fuse-range>
Range (ft) added to Collision and Impact calculations. Defaults to 0.0.
<contents>
A string describing the property where the contents (lbs) of a Submodel are located. Used with droptanks. Set to zero on release. Defaults to "none".
<speed-prop>
A string describing the property where the initial speed of the Submodel is located. Defaults to "none".
<submodel-path>
A string describing the path to the .xml file where the next submodel Initial Conditions are located. This submodel will be instantiated when any of Collision Impact or Expiry are true. Submodels can be linked to any depth using this tag. Defaults to "".
<slaved>
If true the Submodel is slaved to its parent model on release. For a subsequent release, the property "controls/slave-to-ac" must be set to false.
<random>
If true, initial cd is varied by +- 10 %, and life between 50 % and 100 %. Define <randomness> to control the randomness of the azimuth, elevation, cd, and life. Defaults to false.
<randomness>
Contains the following sub-tags:
<azimuth>
Define the variation in degrees around the default azimuth. By default +-0%.
<elevation>
Define the variation in degrees around the default elevation. By default +-0%.
<cd>
Controls how much the Cd is varied. The default is 0.1, which is +-10%.
<life>
Varies the randomness of the submodel's life between 0.0 (0 %) and 1.0 (100 %). Defaults to 0.5 (50 %). Note this is the minimum life, not the variation around the submodel's default life.
<offsets>
Contains the following sub-tags:
<x-m>
Submodel's initial fore/aft position in metres relative to user aircraft. Aft is positive.
<y-m>
Submodel's initial left/right position in metres relative to user aircraft. Right is positive.
<z-m>
Submodel's initial up/down position in metres relative to user aircraft. Up is positive.
<heading-deg>
Submodel's initial azimuth in degrees relative to user aircraft's nose. Right is positive.
<pitch-deg>
Submodel's initial elevation in degrees relative to user aircraft's pitch. Up is positive.

The following tags are deprecated since FlightGear v3.6:

<x-offset>
Submodel's initial fore/aft position in feet relative to user aircraft. Fore is positive.
<y-offset>
Submodel's initial left/right position in feet relative to user aircraft. Right is positive.
<z-offset>
Submodel's initial up/down position in feet relative to user aircraft. Up is positive.
<yaw-offset>
Submodel's initial azimuth in degrees relative to user aircraft's nose. Right is positive.
<pitch-offset>
Submodel's initial elevation in degrees relative to user aircraft's pitch. Up is positive.

Technical stuff

  1. Slaved Objects: Slaved objects follow exactly the movements of their parent object. They can be released, when they then become normal Ballistic objects. They are designed for use as underwing stores, such as droptanks, as they give a realistic appearance on release. On the other hand, there is a small framerate cost. Where the stores are carried in a bombbay, this technique is not required. Here, an acceptable appearance can be achieved by adding models of the stores in the bombbay which are hidden on instantiation of the submodel.
  2. Formations: Wingmen are not AI Aircraft. In the interest of framerate they are in fact a sub-class of slaved objects, with added sinusoidal noise and some simple AI rules. They cannot be released to act independently. The formation can be changed by the use of a Nasal script. There is no collision detection or avoidance, so you must avoid flying the wingmen into each other during a formation change. Thare is a significant framerate cost involved. The wingmen can be as simple or complicated as you wish. The ones currently implemented tend to be fully detailed, and can be "ridden". This is uneccesary, but gives a fun viewpoint of the formation. In due course I will produce a Howto for Wingmen.
  3. Multiplayer: Submodels, indeed all AI objects are not visible over MP. This is in part deliberate (to prevent people trying to shoot at airliners), and in part technical (due to lag on the network the submodels would be nowhere near their actual position). On the other hand, it would be nice to include wingmen and perhaps droptanks in the overall scene. At the moment I cannot come up with a design which works at acceptable framerate cost.

Related content