VISUAL EFFECTS

Visual effects are an important feature of Microsoft Flight Simulator as they can be used to make the world and the SimObjects that inhabit it feel more alive. These effects should always be created using The Visual Effects Editor in the actual simulation, as the editor permits you to have real-time visual feedback on the effects being created. However, it may be necessary to edit an effect after it has been created, or you may wish to simply understand the internal structure of how an effect is created and added to a package, and so these pages can be used to get that information.

All visual effects are packaged as part of a VisualEffectsLib, which will contain one *.vfxlib file and then one or more *.xml files. The *.vfxlib file is what tells the simulation what effects are contained in the package and is itself basically a form of XML file that can be edited in any text editor, if required. The format for this file is as follows:

<VisualEffectLibrary Version="1.0.0">
    <VisualEffect File="[filename1].xml"/>
    <VisualEffect File="[filename2].xml"/>
    <!-- etc... -->
</VisualEffectLibrary>

When you are creating your effects, the general folder structure for saving the *.xml and *.vfxlib files would be:

<FSProject_Folder>\PackageDefinitions\VisualEffectLibs\<CompanyName>\

The different XML files listed in the *.vfxlib file are the files for individual effects. The structure of these individual effect files is explained on the following page:

You can also find fully formatted examples from the following page:

Using Visual Effects

Once you have created your visual effects, you'll need to be able to add them to your SimObjects. This is done by including references to the effect in the Model Definitions file for the SimObject. Visual Effects are contained within Component Templates. The base template for Visual Effects is defined in the FX.xml document, so to start with you need to make sure that you add the following line into a <Behaviors> element:

<Include ModelBehaviorFile="Asobo\Generic\FX.xml"/>

Once you've done that, you can start to use the Component Templates. For this, first add a Component with a unique string ID attribute like this:

<Component ID="#MyFXSpawner#">
</Component>

Inside that component you will need to declare what template you are using, and what parameters of that template you want to change in a <Parameters Type="Override"> section:

<Component ID="MyVFXSpawner">
    <Parameters Type="Override">
    </Parameters>
</Component>

The available default parameter elements are :

  • <FX_GUID>: The GUID of the VFX to spawn. This can be found as the "InstanceID" attribute value of the <VisualEffect.VisualEffect> element in the Visual Effect XML asset source file in the following format:

    {XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}

  • <FX_CODE>: RPN code expression evaluated by the simulator. When it becomes true the Visual Effect is spawned. When it becomes false the Visual Effect is stopped.
  • <FX_CONTACT_POINT_ID>: The index of the ContactPoint you want to attach the effect to. You can use it as a fallback if the node you provided is not found. The default value is -1 which means you don't want to use any contact point (in which case you will you need to provide a valid node, as explained further down this page).
  • <FX_OFFSET_X>: X offset in the coordinate space defined for the Visual Effect, applied to the Visual Effect after spawn (meters, default value is 0).
  • <FX_OFFSET_Y>: Y offset in the coordinate space defined for the Visual Effect, applied to the Visual Effect after spawn (meters, default value is 0)
  • <FX_OFFSET_Z>: Z offset in the coordinate space defined for the Visual Effect, applied to the Visual Effect after spawn (meters, default value is 0)
  • <FX_ROTATION_OFFSET_P>: Pitch rotation angle in local space (degrees, default value is 0)
  • <FX_ROTATION_OFFSET_B>: Bank rotation angle in local space (degrees, default value is 0)
  • <FX_ROTATION_OFFSET_H>: Heading rotation angle in local space (degrees, default value is 0)

If you don't need something else than the default value then you don't need to add the parameter to the override section.

Below is a short example of how this all comes together:

<Component ID="MyVFXSpawner">
    <Parameters Type="Override">
        <FX_GUID>{7E68323C-E75D-4F5B-988E-65DD4956F6BA}</FX_GUID>
        <!-- Always spawn -->
        <FX_CODE>1 0 &gt;</FX_CODE>
        <!-- Spawn on contact point 2 if node not found -->
        <FX_CONTACT_POINT_ID>2</FX_CONTACT_POINT_ID>
        <!-- Offset effect instances up 1 meter -->
        <FX_OFFSET_Y>1.0</FX_OFFSET_Y>
        <!-- Pitch effect instances 90 degrees -->
        <FX_ROTATION_OFFSET_P>90.0</FX_ROTATION_OFFSET_P>
    </Parameters>
</Component>

With that done, you can define each instance of your effect to spawn as a child Component with a unique ID and a Node like this:

<Component ID="MyVFXSpawner">
    <Parameters Type="Override">
        <FX_GUID>{7E68323C-E75D-4F5B-988E-65DD4956F6BA}</FX_GUID>
        <FX_CODE>1 0 &gt;</FX_CODE>
        <FX_CONTACT_POINT_ID>2</FX_CONTACT_POINT_ID>
        <FX_OFFSET_Y>1.0</FX_OFFSET_Y>
        <FX_ROTATION_OFFSET_P>90.0</FX_ROTATION_OFFSET_P>
    </Parameters>
    <Component ID="MyVFXInstance_0" Node="MyNodeName_0">
        <UseTemplate Name="ASOBO_GT_FX"/>
    </Component>
    <Component ID="MyVFXInstance_1" Node="MyNodeName_1">
        <UseTemplate Name="ASOBO_GT_FX"/>
    </Component>
</Component>

Note that the Node attribute is mandatory. Its value must match the name of a node in your model mesh. If you don't want to attach to a node the attribute must still be present - you can put a placeholder value such as "__NO_NODE__" to make sure you don't accidentally match a node in your model - and you must provide a contact point to spawn on with the <FX_CONTACT_POINT_ID> template parameter.

If you want to override some template parameters for a specific instance of your effect you can also do that inside a <UseTemplate> element, EG:

<Component ID="MyVFXSpawner">
    <Parameters Type="Override">
        <FX_GUID>{7E68323C-E75D-4F5B-988E-65DD4956F6BA}</FX_GUID>
        <FX_CODE>1 0 &gt;</FX_CODE>
        <!-- Offset all instances up -->
        <FX_OFFSET_Y>1.0</FX_OFFSET_Y>
    </Parameters>
    <Component ID="MyVFXInstance_Left" Node="MyNode_Left">
        <UseTemplate Name="ASOBO_GT_FX">
            <!-- Offset instance to the left -->
            <FX_OFFSET_X>5.0</FX_OFFSET_X>
        </UseTemplate>
    </Component>
    <Component ID="MyVFXInstance_Right" Node="MyNode_Right">
        <UseTemplate Name="ASOBO_GT_FX">
            <!-- Offset instance to the right -->
            <FX_OFFSET_X>-5.0</FX_OFFSET_X>
        </UseTemplate>
    </Component>
    <Component ID="MyVFXInstance_ContactPoint" Node="__NO_NODE__">
        <UseTemplate Name="ASOBO_GT_FX">
            <!-- Spawn on a contact point instead of a node -->
            <FX_CONTACT_POINT_ID>2</FX_CONTACT_POINT_ID>
            <!-- This instance needs more vertical offset -->
            <FX_OFFSET_Y>8.0</FX_OFFSET_Y>
            <!-- Pitch this instance 90 degrees -->
            <FX_ROTATION_OFFSET_P>90.0</FX_ROTATION_OFFSET_P>
        </UseTemplate>
    </Component>
</Component>

There are also more advanced template parameters that you can use to get further control over the behavior of your Visual Effect:

  • <ENABLE_SURFACE_TYPE_N>: Enumerates the different surface types over which your Visual Effect may spawn. This implicitly disables all other surface types. See the Surface Types section for a full list of names associated with each surface type.
  • <DISABLE_SURFACE_TYPE_N>: Enumerates the surface types over which your Visual Effect may not spawn.
  • <OVERRIDE_SURFACE_TYPE_N>: Enumerates over which surface types your Visual Effect will be replaced by another. The other effect is referenced with a GUID defined in the corresponding <OVERRIDE_FX_SURFACE_TYPE_GUID_N> template parameter.
  • <OVERRIDE_FX_SURFACE_TYPE_GUID_N>: This defines which Visual Effect will replace the one defined by the <FX_GUID> parameter for the corresponding <OVERRIDE_SURFACE_TYPE_N> parameter.
  • <FX_GRAPH_PARAM_N>: This element is used to define a custom parameter and some accompanying RPN code that can then be used in the GraphParameter VFX node. For full details of how this element can be used please see here: Example Using Graph Parameters

The value N for the elements listed above must start at 0 and be incremented sequentially to however many you need. Below is a further example showing how to use these elements:

<Component ID="MyVFXSpawner">
    <Parameters Type="Override">
        <FX_GUID>{7E68323C-E75D-4F5B-988E-65DD4956F6BA}</FX_GUID>
        <FX_CODE>1 0 &gt;</FX_CODE>
        <!-- Allow this FX to spawn only over these 5 surface types -->
        <ENABLE_SURFACE_TYPE_0>CONCRETE</ENABLE_SURFACE_TYPE_0>
        <ENABLE_SURFACE_TYPE_1>ASPHALT</ENABLE_SURFACE_TYPE_1>
        <ENABLE_SURFACE_TYPE_2>BITUMINUS</ENABLE_SURFACE_TYPE_2>
        <ENABLE_SURFACE_TYPE_3>MACADAM</ENABLE_SURFACE_TYPE_3>
        <ENABLE_SURFACE_TYPE_4>TARMAC</ENABLE_SURFACE_TYPE_4>
    </Parameters>
    <Component ID="MyVFXInstance_Small" Node="MyNode_Small">
        <UseTemplate Name="ASOBO_GT_FX">
            <FX_OFFSET_X>5.0</FX_OFFSET_X>
            <!-- Parameter fed to the graph to compute the size of the particles -->
            <FX_GRAPH_PARAM_0>InitialSize, (A:GROUND VELOCITY, knots) 50 /<FX_GRAPH_PARAM_0>
        </UseTemplate>
    </Component>
    <Component ID="MyVFXInstance_Large" Node="MyNode_Large">
        <UseTemplate Name="ASOBO_GT_FX">
            <!-- Spawn another FX when flying over Concrete or Asphalt-->
            <OVERRIDE_SURFACE_TYPE_0>CONCRETE</OVERRIDE_SURFACE_TYPE_0>
            <OVERRIDE_FX_SURFACE_TYPE_GUID_0>{A8CEDC03-94A2-4B18-89C7-2DCD96CC83DE}</OVERRIDE_FX_SURFACE_TYPE_GUID_0>
            <OVERRIDE_SURFACE_TYPE_1>ASPHALT</OVERRIDE_SURFACE_TYPE_1>
            <OVERRIDE_FX_SURFACE_TYPE_GUID_1>{A8CEDC03-94A2-4B18-89C7-2DCD96CC83DE}</OVERRIDE_FX_SURFACE_TYPE_GUID_1>
            <!-- Parameter fed to the graph to compute the size of the particles -->
            <FX_GRAPH_PARAM_0>InitialSize, (A:GROUND VELOCITY, knots) 10 /<FX_GRAPH_PARAM_0>
        </UseTemplate>
    </Component>
</Component>

Please see the Model Behavior Example on the main examples page for a complete version of a Visual Effect added to the <Behavior> element. There is also a page dedicated to showing how to use specific model <Behavior> templates for VFX:

Surface Types

Below is a list of the viable names that can be used for surface types when using the <ENABLE_SURFACE_TYPE_N>, <DISABLE_SURFACE_TYPE_N>, or <OVERRIDE_SURFACE_TYPE_N> elements in the VFX templates:

  • CONCRETE
  • GRASS
  • WATER_FSX
  • GRASS_BUMPY
  • ASPHALT
  • SHORT_GRASS
  • LONG_GRASS
  • HARD_TURF
  • SNOW
  • ICE
  • URBAN
  • FOREST
  • DIRT
  • CORAL
  • GRAVEL
  • OIL_TREATED
  • STEEL_MATS
  • BITUMINUS
  • BRICK
  • MACADAM
  • PLANKS
  • SAND
  • SHALE
  • TARMAC
  • WRIGHT_FLYER_TRACK
  • OCEAN
  • WATER
  • POND
  • LAKE
  • RIVER
  • WASTE_WATER
  • PAINT