ILS in HUD
The FlightGear forum has a subforum related to: Canvas |
Adding ILS to the HUD of an SU-37
This is just one way of implementing this on a particular aircraft. Even on this aircraft there are many ways of achieving this. Apart from the SU-37-set.xml file that will need to be amended manually, the other files are available in this dropbox folder.
A piece of glass to draw on
First of all a surface is required to draw on using Canvas. The needs to be a 3d-model in AC3d format. For this SU-37 example, the file hudGlass.ac was used. These file types are saved as text files, this one being:
AC3Db
MATERIAL "ac3dmat4" rgb 1 0.5 0 amb 0.2 0.2 0.2 emis 1 0.8 0.6 spec 0.2 0.2 0.2 shi 128 trans 0.5
OBJECT world
kids 1
OBJECT poly
name "PFD-Screen"
loc -1.81012e-05 9.69689e-06 0.138677
texture "Aircraft/SU-37/Hud/screen-test.png"
texoff -0.036 -0.073
crease 45.000000
numvert 4
0 0.106446 -0.052729
0 0.106446 -0.224199
0 -0.106446 -0.224199
0 -0.106446 -0.052729
numsurf 1
SURF 0x30
mat 0
refs 4
3 0 0
2 1 0
1 1 1
0 0 1
kids 0
Note For this to work, the surface (known as PFD-Screen in this example MUST be textured. Pretty much anything will do because Canvas replaces this texture with its own creation. Here the file specifies Aircraft/SU-37/Hud/screen-test.png as the texture file. Obviously, this file must exist, must be a graphics file (JPEG, PNG, etc.) and must be where is says it is. Here, it would need to be in the Aircraft/SU-37/Hud folder. See also AC files: Basic changes to textures and colors. |
Placing the glass in the cockpit
This example used an extra model by adding some extra lines in the SU-37-set.xml file, following the main model:
<?xml version="1.0"?>
<PropertyList>
<!-- ... -->
<!-- New lines -->
<model>
<path>Aircraft/SU-37/Hud/canvas-ILS.xml</path>
</model>
<!-- ... -->
</PropertyList>
The file canvas-ILS.xml contains the following:
<?xml version="1.0"?>
<PropertyList>
<path>Aircraft/SU-37/Hud/hudGlass.ac</path>
<offsets>
<heading-deg>0</heading-deg>
<roll-deg>0</roll-deg>
<pitch-deg>40</pitch-deg>
<x-m>4.55</x-m>
<y-m>-0.005 </y-m>
<z-m>1.415</z-m>
</offsets>
</PropertyList>
This defines the piece of glass to be used (Aircraft/SU-37/Hud/hudGlass.ac) and positions it in a convenient place.
ILS properies
The properties required to place ILS "needles" in a HUD are:
/instrumentation/nav/heading-needle-deflection
/instrumentation/nav/gs-needle-deflection
/instrumentation/nav/gs-in-range
/instrumentation/nav/in-range
To be certain of these being recognised properly (i.e., as the correct types) it might be advisable to declare them in the aircraft-set.xml file between the <instrumentation>
and the </instrumentation>
tags:
<?xml version="1.0"?>
<PropertyList>
<!-- ... -->
<instrumentation>
<!-- ... -->
<nav>
<heading-needle-deflection type="double">10.0</heading-needle-deflection>
<in-range type="bool">0</in-range>
<gs-needle-deflection type="double">10.0</gs-needle-deflection>
<gs-in-range type="bool">0</gs-in-range>
</nav>
<!-- ... -->
</instrumentation>
<!-- ... -->
</PropertyList>
Drawing the ILS needles on the glass
This ILS example uses a derivative of the code at Canvas HUD
# ==============================================================================
# Head up display ILS extras for SU-37
# ==============================================================================
var HUD = {
canvas_settings: {
"name": "HUD",
"size": [1024, 1024],
"view": [640, 640],
"mipmapping": 1
},
new: func(placement) {
var m = {
parents: [HUD],
canvas: canvas.new(HUD.canvas_settings)
};
m.canvas.addPlacement(placement);
m.canvas.setColorBackground(1, 0, 0, 0.02);
m.root =
m.canvas.createGroup()
.setScale(1, 2)
.setTranslation(320, 320)
.set("font", "LiberationFonts/LiberationMono-Regular.ttf")
.setDouble("character-size", 9)
.setDouble("character-aspect-ration", 0.45)
.set("stroke", "rgba(255,0,0,0.9)");
m.text =
m.root.createChild("group")
.set("fill", "rgba(255,0,0,0.9)");
# ------------------------------------------------------------------------ ILS deflections
# horizontal needle deflection text box (left/right)
m.hnd =
m.text.createChild("text")
.setDrawMode(3)
.setPadding(2)
.setAlignment("center-top")
.setTranslation(0, -135);
# vertical needle deflection text box (up/down)
m.vnd =
m.text.createChild("text")
.setDrawMode(3)
.setPadding(2)
.setAlignment("center-top")
.setTranslation(200, 0);
# Radar altitude (for below 1,000 ft AGL)
m.rad_alt =
m.text.createChild("text")
.setFontSize(18, 0.9)
.setAlignment("center-top")
.setTranslation(0, 120);
# Waterline / Pitch indicator (used for alignment with main HUD)
m.root.createChild("path")
.moveTo(-24, 0)
.horizTo(-8)
.lineTo(-4, 6)
.lineTo(0, 0)
.lineTo(4, 6)
.lineTo(8, 0)
.horizTo(24)
.setStrokeLineWidth(0.9);
# ------------------------------------------------- ILS glide slope/localiser beam needles
# glide slope indicator
m.gsi = m.root.createChild("group", "GSI");
m.gsi.createChild("path")
.moveTo(8, 0)
.arcSmallCCW(8, 8, 0, -16, 0)
.arcSmallCCW(8, 8, 0, 16, 0)
.moveTo(-4, 0)
.horiz(-150)
.moveTo(4, 0)
.horiz(150)
.setStrokeLineWidth(2.0);
# localiser beam indicator
m.lbi = m.root.createChild("group", "GSI");
m.lbi.createChild("path")
.moveTo(8, 0)
.arcSmallCCW(8, 8, 0, -16, 0)
.arcSmallCCW(8, 8, 0, 16, 0)
.moveTo(0, -4)
.vert(-100)
.moveTo(0, 4)
.vert(200)
.setStrokeLineWidth(2.0);
# ---------------------------------------------------------------------------------------
m.input = {
hnd: "/instrumentation/nav/heading-needle-deflection",
snd: "/instrumentation/nav/gs-needle-deflection",
gsir: "/instrumentation/nav/gs-in-range",
hir: "/instrumentation/nav/in-range",
rad_alt: "/position/altitude-agl-ft",
wow_nlg: "/gear/gear[4]/wow"
};
foreach(var name; keys(m.input)){
m.input[name] = props.globals.getNode(m.input[name], 1);
}
return m;
},
# ------------------------------------------------------------------------------- update
update: func() {
var rad_alt = me.input.rad_alt.getValue(); # Only show below 1000 ft AGL
if(rad_alt and rad_alt < 1000){
rad_alt = sprintf("%4d AGL", rad_alt);
} else {
rad_alt = nil;
}
me.rad_alt.setText(rad_alt);
# the Left/right needle
gslr = me.input.hnd.getValue();
hir = me.input.hir.getValue();
me.hnd.setText(sprintf("%1.3f", gslr));
if(hir == 0) gslr = 10.8;
me.lbi.setTranslation(20 * gslr, 0);
# The Glide Slope Up/Down needle
gsud = me.input.snd.getValue();
gsir = me.input.gsir.getValue();
me.vnd.setText(sprintf("%1.3f", gsud));
if(gsir == 0) gsud = 7.2;
me.gsi.setTranslation(0, -20 * gsud);
settimer(func(){ me.update(); }, 0);
} # ---------------------------------------------------------------------- end of update
}; # end of HUD
var init = setlistener("/sim/signals/fdm-initialized", func(){
removelistener(init); # only call once
var hud_pilot = HUD.new({"node": "PFD-Screen"});
hud_pilot.update();
});
It was saved as hudCanvasILS.nas in the Aircraft/SU-37/Hud folder
Getting the Nasal to run
Adding this line in the nasal section at the bottom of the SU-37-set.xml file will make the ILS script load and run with the aircraft
<?xml version="1.0"?>
<PropertyList>
<!-- ... -->
<nasal>
<canvas_test>
<file>Aircraft/SU-37/Hud/hudCanvasILS.nas</file>
</canvas_test>
<!-- ... -->
</nasal>
</PropertyList>
What to expect
Tutorial written by Warty