Canvas HUD: Difference between revisions
Jump to navigation
Jump to search
(Created page with "{{Template:Canvas Navigation}} {{stub}} Rendering a basic HUD with a Canvas. thumb|C-130J basic HUD <syntaxhighlight lang="php"> # ==...") |
(Add energy and acceleration cues and do some cleanup) |
||
Line 14: | Line 14: | ||
var vec_length = func(x, y) { return math.sqrt(pow2(x) + pow2(y)); }; | var vec_length = func(x, y) { return math.sqrt(pow2(x) + pow2(y)); }; | ||
var round0 = func(x) { return math.abs(x) > 0.01 ? x : 0; }; | var round0 = func(x) { return math.abs(x) > 0.01 ? x : 0; }; | ||
var clamp = func(x, min, max) { return x < min ? min : (x > max ? max : x); } | |||
var HUD = { | var HUD = { | ||
Line 26: | Line 27: | ||
var m = { | var m = { | ||
parents: [HUD], | parents: [HUD], | ||
canvas: canvas.new(HUD.canvas_settings) | canvas: canvas.new(HUD.canvas_settings) | ||
}; | }; | ||
m.canvas.addPlacement(placement); | m.canvas.addPlacement(placement); | ||
m.canvas.setColorBackground(0.36, 1, 0.3, 0.02); | m.canvas.setColorBackground(0.36, 1, 0.3, 0.02); | ||
m.root = m.canvas.createGroup(); | |||
m.root = | |||
m.canvas.createGroup() | |||
.setScale(1, 1/math.cos(25 * math.pi/180)) | |||
.setTranslation(240, 180) | |||
.set("font", "LiberationFonts/LiberationMono-Regular.ttf") | |||
.setDouble("character-size", 18) | |||
.setDouble("character-aspect-ration", 0.9) | |||
.set("stroke", "rgba(0,255,0,0.9)"); | |||
m.text = | |||
m.root.createChild("group") | |||
.set("fill", "rgba(0,255,0,0.9)"); | |||
# Heading | # Heading | ||
m.hdg = m. | m.hdg = | ||
m.text.createChild("text") | |||
.setDrawMode(3) | |||
.setPadding(2) | |||
.setAlignment("center-top") | |||
.setTranslation(0, -140); | |||
# Airspeed | # Airspeed | ||
m.airspeed = m. | m.airspeed = | ||
m.text.createChild("text") | |||
.setAlignment("right-center") | |||
.setTranslation(-180, 0); | |||
# Groundspeed | # Groundspeed | ||
m.groundspeed = m. | m.groundspeed = | ||
m.text.createChild("text") | |||
.setAlignment("left-center") | |||
.setTranslation(-220, 90); | |||
# Vertical speed | # Vertical speed | ||
m.vertical_speed = m. | m.vertical_speed = | ||
m.text.createChild("text") | |||
.setFontSize(10, 0.9) | |||
.setAlignment("right-center") | |||
.setTranslation(205, 50); | |||
# Radar altidude | # Radar altidude | ||
m.rad_alt = m. | m.rad_alt = | ||
m.text.createChild("text") | |||
.setAlignment("right-center") | |||
.setTranslation(220, 70); | |||
# Waterline / Pitch indicator | # Waterline / Pitch indicator | ||
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); | |||
# Flightpath/Velocity vector | # Flightpath/Velocity vector | ||
m. | m.fpv = m.root.createChild("group", "FPV"); | ||
m.fpv.createChild("path") | |||
.moveTo(8, 0) | |||
.arcSmallCCW(8, 8, 0, -16, 0) | |||
.arcSmallCCW(8, 8, 0, 16, 0) | |||
.moveTo(-8, 0) | |||
.horiz(-16) | |||
.moveTo(8, 0) | |||
.horiz(16) | |||
.setStrokeLineWidth(0.9); | |||
# Energy/Acceleration cues | |||
m.energy_cue = | |||
m.fpv.createChild("path") | |||
.setStrokeLineWidth(1); | |||
m.acc = | |||
m.fpv.createChild("path") | |||
.setStrokeLineWidth(1); | |||
# Horizon | # Horizon | ||
Line 111: | Line 115: | ||
m.h_rot = m.horizon_group.createTransform(); | m.h_rot = m.horizon_group.createTransform(); | ||
# Pitch lines | |||
for(var i = 5; i <= 10; i += 5) | for(var i = 5; i <= 10; i += 5) | ||
{ | |||
m.horizon_group.createChild("path") | m.horizon_group.createChild("path") | ||
.moveTo(24, -i * 18) | .moveTo(24, -i * 18) | ||
Line 119: | Line 125: | ||
.horiz(-48) | .horiz(-48) | ||
.vert(7) | .vert(7) | ||
.setStrokeLineWidth(1.5) | .setStrokeLineWidth(1.5); | ||
} | |||
# Horizon line | # Horizon line | ||
m.horizon_group.createChild("path") | |||
.moveTo(-500, 0) | |||
.horizTo(500) | |||
.setStrokeLineWidth(1.5); | |||
m.input = { | m.input = { | ||
pitch: | pitch: "/orientation/pitch-deg", | ||
roll: | roll: "/orientation/roll-deg", | ||
hdg: | hdg: "/orientation/heading-deg", | ||
speed_n: | speed_n: "velocities/speed-north-fps", | ||
speed_e: | speed_e: "velocities/speed-east-fps", | ||
speed_d: | speed_d: "velocities/speed-down-fps", | ||
alpha: | alpha: "/orientation/alpha-deg", | ||
beta: | beta: "/orientation/side-slip-deg", | ||
ias: | ias: "/velocities/airspeed-kt", | ||
gs: | gs: "/velocities/groundspeed-kt", | ||
vs: | vs: "/velocities/vertical-speed-fps", | ||
rad_alt: | rad_alt: "/instrumentation/radar-altimeter/radar-altitude-ft", | ||
wow_nlg: | wow_nlg: "/gear/gear[4]/wow", | ||
airspeed: "/velocities/airspeed-kt", | |||
target_spd: "/autopilot/settings/target-speed-kt", | |||
acc: "/fdm/jsbsim/accelerations/udot-ft_sec2" | |||
}; | }; | ||
Line 196: | Line 203: | ||
var dir_x = math.atan2(round0(vel_by), math.max(vel_bx, 0.01)) * 180.0 / math.pi; | var dir_x = math.atan2(round0(vel_by), math.max(vel_bx, 0.01)) * 180.0 / math.pi; | ||
me. | me.fpv.setTranslation(dir_x * 18, dir_y * 18); | ||
var speed_error = 0; | |||
if( me.input.target_spd.getValue() != nil ) | |||
speed_error = 4 * clamp( | |||
me.input.target_spd.getValue() - me.input.airspeed.getValue(), | |||
-15, 15 | |||
); | |||
me.energy_cue.reset(); | |||
# if( math.abs(speed_error) > 3 ) | |||
me.energy_cue.moveTo(-22, 0) | |||
.vert(speed_error) | |||
.horiz(3) | |||
.vertTo(0); | |||
var acc = me.input.acc.getValue() or 0; | |||
me.acc.reset() | |||
.moveTo(-34, -acc * 5 - 4) | |||
.line(8, 4) | |||
.line(-8, 4); | |||
settimer(func me.update(), 0); | settimer(func me.update(), 0); |
Revision as of 16:07, 5 November 2012
The FlightGear forum has a subforum related to: Canvas |
This article is a stub. You can help the wiki by expanding it. |
Rendering a basic HUD with a Canvas.
# ==============================================================================
# Head up display
# ==============================================================================
var pow2 = func(x) { return x * x; };
var vec_length = func(x, y) { return math.sqrt(pow2(x) + pow2(y)); };
var round0 = func(x) { return math.abs(x) > 0.01 ? x : 0; };
var clamp = func(x, min, max) { return x < min ? min : (x > max ? max : x); }
var HUD = {
canvas_settings: {
"name": "HUD",
"size": [1024, 1024],
"view": [480, 360],
"mipmapping": 1
},
new: func(placement)
{
var m = {
parents: [HUD],
canvas: canvas.new(HUD.canvas_settings)
};
m.canvas.addPlacement(placement);
m.canvas.setColorBackground(0.36, 1, 0.3, 0.02);
m.root =
m.canvas.createGroup()
.setScale(1, 1/math.cos(25 * math.pi/180))
.setTranslation(240, 180)
.set("font", "LiberationFonts/LiberationMono-Regular.ttf")
.setDouble("character-size", 18)
.setDouble("character-aspect-ration", 0.9)
.set("stroke", "rgba(0,255,0,0.9)");
m.text =
m.root.createChild("group")
.set("fill", "rgba(0,255,0,0.9)");
# Heading
m.hdg =
m.text.createChild("text")
.setDrawMode(3)
.setPadding(2)
.setAlignment("center-top")
.setTranslation(0, -140);
# Airspeed
m.airspeed =
m.text.createChild("text")
.setAlignment("right-center")
.setTranslation(-180, 0);
# Groundspeed
m.groundspeed =
m.text.createChild("text")
.setAlignment("left-center")
.setTranslation(-220, 90);
# Vertical speed
m.vertical_speed =
m.text.createChild("text")
.setFontSize(10, 0.9)
.setAlignment("right-center")
.setTranslation(205, 50);
# Radar altidude
m.rad_alt =
m.text.createChild("text")
.setAlignment("right-center")
.setTranslation(220, 70);
# Waterline / Pitch indicator
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);
# Flightpath/Velocity vector
m.fpv = m.root.createChild("group", "FPV");
m.fpv.createChild("path")
.moveTo(8, 0)
.arcSmallCCW(8, 8, 0, -16, 0)
.arcSmallCCW(8, 8, 0, 16, 0)
.moveTo(-8, 0)
.horiz(-16)
.moveTo(8, 0)
.horiz(16)
.setStrokeLineWidth(0.9);
# Energy/Acceleration cues
m.energy_cue =
m.fpv.createChild("path")
.setStrokeLineWidth(1);
m.acc =
m.fpv.createChild("path")
.setStrokeLineWidth(1);
# Horizon
m.horizon_group = m.root.createChild("group");
m.h_trans = m.horizon_group.createTransform();
m.h_rot = m.horizon_group.createTransform();
# Pitch lines
for(var i = 5; i <= 10; i += 5)
{
m.horizon_group.createChild("path")
.moveTo(24, -i * 18)
.horiz(48)
.vert(7)
.moveTo(-24, -i * 18)
.horiz(-48)
.vert(7)
.setStrokeLineWidth(1.5);
}
# Horizon line
m.horizon_group.createChild("path")
.moveTo(-500, 0)
.horizTo(500)
.setStrokeLineWidth(1.5);
m.input = {
pitch: "/orientation/pitch-deg",
roll: "/orientation/roll-deg",
hdg: "/orientation/heading-deg",
speed_n: "velocities/speed-north-fps",
speed_e: "velocities/speed-east-fps",
speed_d: "velocities/speed-down-fps",
alpha: "/orientation/alpha-deg",
beta: "/orientation/side-slip-deg",
ias: "/velocities/airspeed-kt",
gs: "/velocities/groundspeed-kt",
vs: "/velocities/vertical-speed-fps",
rad_alt: "/instrumentation/radar-altimeter/radar-altitude-ft",
wow_nlg: "/gear/gear[4]/wow",
airspeed: "/velocities/airspeed-kt",
target_spd: "/autopilot/settings/target-speed-kt",
acc: "/fdm/jsbsim/accelerations/udot-ft_sec2"
};
foreach(var name; keys(m.input))
m.input[name] = props.globals.getNode(m.input[name], 1);
return m;
},
update: func()
{
me.airspeed.setText(sprintf("%d", me.input.ias.getValue()));
me.groundspeed.setText(sprintf("G %3d", me.input.gs.getValue()));
me.vertical_speed.setText(sprintf("%.1f", me.input.vs.getValue() * 60.0 / 1000));
var rad_alt = me.input.rad_alt.getValue();
if( rad_alt and rad_alt < 5000 ) # Only show below 5000AGL
rad_alt = sprintf("R %4d", rad_alt);
else
rad_alt = nil;
me.rad_alt.setText(rad_alt);
me.hdg.setText(sprintf("%03d", me.input.hdg.getValue()));
me.h_trans.setTranslation(0, 18 * me.input.pitch.getValue());
var rot = -me.input.roll.getValue() * math.pi / 180.0;
me.h_rot.setRotation(rot);
# flight path vector (FPV)
var vel_gx = me.input.speed_n.getValue();
var vel_gy = me.input.speed_e.getValue();
var vel_gz = me.input.speed_d.getValue();
var yaw = me.input.hdg.getValue() * math.pi / 180.0;
var roll = me.input.roll.getValue() * math.pi / 180.0;
var pitch = me.input.pitch.getValue() * math.pi / 180.0;
var sy = math.sin(yaw); var cy = math.cos(yaw);
var sr = math.sin(roll); var cr = math.cos(roll);
var sp = math.sin(pitch); var cp = math.cos(pitch);
var vel_bx = vel_gx * cy * cp
+ vel_gy * sy * cp
+ vel_gz * -sp;
var vel_by = vel_gx * (cy * sp * sr - sy * cr)
+ vel_gy * (sy * sp * sr + cy * cr)
+ vel_gz * cp * sr;
var vel_bz = vel_gx * (cy * sp * cr + sy * sr)
+ vel_gy * (sy * sp * cr - cy * sr)
+ vel_gz * cp * cr;
var dir_y = math.atan2(round0(vel_bz), math.max(vel_bx, 0.01)) * 180.0 / math.pi;
var dir_x = math.atan2(round0(vel_by), math.max(vel_bx, 0.01)) * 180.0 / math.pi;
me.fpv.setTranslation(dir_x * 18, dir_y * 18);
var speed_error = 0;
if( me.input.target_spd.getValue() != nil )
speed_error = 4 * clamp(
me.input.target_spd.getValue() - me.input.airspeed.getValue(),
-15, 15
);
me.energy_cue.reset();
# if( math.abs(speed_error) > 3 )
me.energy_cue.moveTo(-22, 0)
.vert(speed_error)
.horiz(3)
.vertTo(0);
var acc = me.input.acc.getValue() or 0;
me.acc.reset()
.moveTo(-34, -acc * 5 - 4)
.line(8, 4)
.line(-8, 4);
settimer(func me.update(), 0);
}
};
var init = setlistener("/sim/signals/fdm-initialized", func() {
removelistener(init); # only call once
var hud_pilot = HUD.new({"node": "HUD.l.canvas"});
hud_pilot.update();
# var hud_copilot = HUD.new({"node": "HUD.l.canvas.001"});
# hud_copilot.update();
});