How to Use VHL Interface Data in Custom Unity Scripts

This page describes how to use data from a Vortex VHL interface in a custom Unity script. This is a simply way to implement custom behavior or logic in Unity using data in a distributed Vortex simulation.

Overview

First of all, to manually create assets for the VHL Interface, a Unity project with the Vortex Integration Package is needed (such as VortexUnityTools or your own project). 

For an overview of the assets workflow, refer to How to associate Vortex Objects with Unity prefabs. VHL Interface follows the same pattern as for other supported features:

  • A prefab must be made and associated to a VHL Interface. They must share the same name.
  • The prefab must have a component attached to it: the VortexVHL component.
  • The prefab must be in an asset bundle. The asset bundle must have the same file name and path as the Vortex document (vxscene, mechanism, etc.) that contains the VHL interface.

Creating a Prefab for a VHL Interface

With the Vortex Studio Integration package installed, it is quite simple to create a prefab for a specific Vortex VHL interface. Here is a short guide:

  1. First, identify which VHL interface you want to access from Unity. This can be done by opening any Vortex file that supports VHL interfaces, such as mechanisms, assemblies, scenes and graphics galleries.
  2. Then, from the Unity Editor, create a new empty GameObject. This can be done by right-clicking the Hierarchy window and selecting Create Empty.

  3. Copy the name of your Vortex VHL instance, and set it as this new GameObject's name. This will be the root of your prefab.
  4. Add a VortexVHL component on this GameObject. This class allows to access VHL interface data from Unity.
  5. From there, the prefab's content and behavior is up to you, the user. Typically, a custom script is added to this GameObject, alongside VortexVHL component. From the script, you can access any VHL input, output or parameter; as is described in the following section.

Using the VortexVHL Component in a Script

To use the data in a script, the prefab must contain a script component:  it is in such a script that the VHL interface's data can be accessed. To do this, you first need to get a reference to the VortexVHL component. It is recommended to do this in the Start or Awake method, then re-use it as needed. From this reference, the following methods can be used to access the data from a VHL interface's field.

Return Data TypeGet Input Field MethodGet Output Field MethodGet Parameter Field MethodAdditional Notes
boolGetInputBoolGetOutputBoolGetParameterBool
intGetInputIntGetOutputIntGetParameterInt
doubleGetInputRealGetOutputRealGetParameterReal
stringGetInputStringGetOutputStringGetParameterString
UnityEngine.Vector2GetInputVector2GetOutputVector2GetParameterVector2Vortex Vector 2 of double values.
UnityEngine.Vector3GetInputVector3GetOutputVector3GetParameterVector3Vortex Vector 3 of double values.
UnityEngine.Vector3GetInputVector3AsPositionGetOutputVector3AsPositionGetParameterVector3AsPositionVector 3, assumed as position information. It is converted from Vortex to Unity coordinate system.
UnityEngine.Vector4GetInputVector4GetOutputVector4GetParameterVector4

Vortex Vector 4 of double values.

UnityEngine.ColorGetInputColorGetOutputColorGetParameterColorVortex Color of float values
UnityEngine.Matrix4x4GetInputMatrixGetOutputMatrixGetParameterMatrixVortex Matrix44 represented by Unity's Matrix4x4 type. No conversion is done whatsoever.
Vortex.Types.PositionRotationGetInputMatrixAsPositionRotationGetOutputMatrixAsPositionRotationGetParameterMatrixAsPositionRotation

Matrix4x4, interpreted as transform information into the PositionRotation class, which contains a position vector, rotation quaternion, and scale vector adapted from Vortex to Unity coordinate system. These can be used directly to assign to Unity Transform component's position, rotation and scale properties.

stringGetInputExtensionNameGetOutputExtensionNameGetParameterExtensionName

All these methods take the same argument: the string corresponding to the field name. When using these methods, if a field is not found, an error will appear in the log and the value returned will be a default value.

Please note that for your custom script to be tied to your asset bundle and usable with the default Vortex Unity application, you need to follow the process described in this guide: How to use custom scripts with Unity asset bundles.

VHL Interface Script Example

Here is an example of a script that uses a VHL interface to display some Vortex data in Unity. 

Sample Script
using UnityEngine;
using Vortex;

public class DisplayVHLData : MonoBehaviour
{
	private Vortex.VortexVHL vhl = null;
	public UnityEngine.UI.Text speedText = null;
	public UnityEngine.UI.Text distanceText = null;
	public UnityEngine.UI.Image engineImage = null;

	void Awake()
	{
		vhl = GetComponent<Vortex.VortexVHL>();
	}

	void FixedUpdate()
	{
        if (speedText != null)
        {
            double speed = vhl.GetInputReal("Speed");
			// Displays speed with 2 decimals format
            speedText.text = $"Current Speed: { speed.ToString("F2") }";
        }

        if (engineImage != null)
        {
            bool engineOn = vhl.GetInputBool("Engine Active");
            engineImage.enabled = engineOn;
        }

        if (distanceText != null)
        {
			double distance = vhl.GetOutputReal("Distance");
			// Displays distance with 2 decimals format
			distanceText.text = $"Distance Moved: { distance.ToString("F2")}";
		}
	}
}

Here is how this script is attached to a prefab with the proper components and references to them:

And here is the VHL interface as defined in a mechanism in the Vortex Editor:

Once the asset bundle has been built and placed next to its corresponding mechanism, it can be loaded and the simulation can be started. The display will be added to the simulation and updated by the script.

.

Using VortexVHL dynamic fields

For ease of use, the VortexVHL component exposes dynamic fields. The member Inputs, Outputs and Parameters are object extending C# System.Dynamic.DynamicObject. For example, a VHL input property named "Velocity" can be access by writing vhl.Inputs.Velocity. There is a few things to keep in mind while using this feature.

  • The dynamic fields are subject to the same limitations as C# DynamicObject 
    This means the properties can't be reserved words such as double, return, bool, etc. This also means you can't use extension methods directly.

    // double myDouble = vhl.Inputs.double;         // ERROR: double is a C# reserved keyword
    // Vector3 myPosition = vhl.Outputs.Position.MyExtensionMethod();  // ERROR: CS1973: Vector3<dynamic> has no applicable method named MyExtensionMethod()
    
    Vector3 myPosition = vhl.Outputs.Position;
    myPosition = myPosition.MyExtensionMethod();    // OK
  • Property's names are case sensitive

  • Non-alphanumeric characters are replaced with underscores
    Vortex allows field's properties to contain character that can't be used to form valid C# identifiers such as space, parenthesis, punctuation to name a few. These properties can be access by replacing the non-alphanumeric values with underscores. For example, the VHL input property "Desired Velocity" can be access with vhl.Inputs.Desired_Velocity, and the VHL output property "My output (5)" can be access with vhl.Outpus.My_output__5_. Notice the double underscore between output and 5: this is because the space and the opening parenthesis both account for one underscore.

  • Values are returned as raw values
    Objects like Vector3 and Matrix4x4 are returned as raw values. A Vector3 representing a position in Vortex frame of reference would need to be converted to Unity referential with ConversionUtilities.VortexToUnityVector. Similarly, a Matrix4x4 transformation matrix in the Vortex frame of reference also needs to be converted with ConversionUtilities.VortexToUnityPositionRotation.

Dynamic Field Usage Example

The following figures shows a VHL interface configuration and a script sample demonstrating how to use the dynamic fields.

Dynamic Fields
using UnityEngine;
using Vortex;

public class DynamicVHLData : MonoBehaviour
{
	private Vortex.VortexVHL vhl = null;
	public bool myBool = false;
	public Color myColor = null;
	public string myString = null;

	void Awake()
	{
		vhl = GetComponent<Vortex.VortexVHL>();
	}

	void FixedUpdate()
	{
        myBool = vhl.Inputs.isActive;        // yields true
        myColor = vhl.Outputs.My_color;      // yields a new UnityEngine.Color(1,1,1,1)
        myString = vhl.Parameters.Texture;   // yields "default texture"
	}
}