Howto:Make full spherical panorama

From FlightGear wiki
Jump to: navigation, search
Note  Also see FlightGear WorldTerrain SkyBox Server for a FlightGear-based approach to procedurally create cubemap textures using FlightGear itself.

In this howto I will explain how to make full spherical panorama in FlightGear. To see many examples of spherical panorama, take a look at this forum thread: http://forum.flightgear.org/viewtopic.php?f=19&t=7713. The semi-automated process is useful for everyone that wants to contribute to the flightgear wiki by adding one of this panorama to each aircraft's page in order to display the cockpit. Here is an example of what can be achieved:

A full spherical panorama of the 3d cessna c172p cockpit

The tools

In order to take panorama in flightgear you need:

  • of course Flightgear
  • a panorama stitching tool. I suggest to use Hugin: it's free and very powerful.

The automatic process

To make the process easier I've created a nasal script that capture automagically the required screenshots. This script can be binded to a keyboard key. Also I've created a standard Hugin file to assemble this screenshots into a full spherical panorama. To get rid of the popup window telling you that the screenshots was saved, you can follow this guidance: http://forum.flightgear.org/viewtopic.php?f=17&t=13810#p140388

Taking the required screenshots

The easier way is to bind the following nasal script to a keyboard key (The F3 key that is used by default to take screenshots). To do this, open the file keyboard.xml that you can find in the fgdata folder with a text editor and look for the following section:

 <key n="259">
  <name>F3</name>
  <desc>Capture screen</desc>
  <binding>
   <command>nasal</command>
   <script>
     var success = fgcommand("screen-capture");
     var path = getprop("/sim/paths/screenshot-last");
     if (success)
         gui.popupTip("Screenshot written to '" ~ path ~ "'");
     else
         gui.popupTip("Error writing screenshot '" ~ path ~ "'");
   </script>
  </binding>
  <mod-shift>
   <desc>Load panel</desc>
   <binding>
    <command>panel-load</command>
   </binding>
  </mod-shift>
 </key>

Now substitute the nasal code between the <script> tags with this:

	var tick_time=3;
        
	menubarvalue=getprop("/sim/menubar/visibility");
	znearvalue=("sim/rendering/camera-group/znear");
	fovvalue=getprop("/sim/current-view/field-of-view");
	freezemvalue=getprop("/sim/freeze/master");
	freezecvalue=getprop("/sim/freeze/clock");
	headingvalue=getprop("/sim/current-view/heading-offset-deg");
	pitchvalue=getprop("/sim/current-view/pitch-offset-deg");
          
	setprop("/sim/menubar/visibility", 'false');
	setprop("/sim/rendering/camera-group/znear",0.03);
	setprop("/sim/current-view/field-of-view", 120);
	setprop("/sim/freeze/master",'true');
	setprop("/sim/freeze/clock",'true');

	var rotatescreen = func(heading_deg, pitch_deg)
	{
		setprop("/sim/current-view/goal-heading-offset-deg", heading_deg);
		setprop("/sim/current-view/heading-offset-deg", heading_deg);
		setprop("/sim/current-view/goal-pitch-offset-deg", pitch_deg);
		setprop("/sim/current-view/pitch-offset-deg", pitch_deg);
	}

	var takescreen = func(heading_deg, pitch_deg)
	{
		print ("taking screen with heading= ", heading_deg, " and pitch= ", pitch_deg);
		var success = fgcommand("screen-capture");
		if (success) 
		{ 
			print ("screen taken with heading= ", heading_deg, " and pitch= ", pitch_deg);
		} 
		else
		{
			print("screen not taken");
		}
	}

	var scr_ticks = func()
	{
		i=getprop("/sim/screenshots/i");
		j=getprop("/sim/screenshots/j");
		k=getprop("/sim/screenshots/k");
		if (i==0)
		{
			pitch_deg=-45;
		}
		else
		{
			pitch_deg=45;
		}
		heading_deg=j*(-90);
		if (k==0)
		{
			rotatescreen(heading_deg, pitch_deg);
			setprop("/sim/screenshots/k", 1);
			settimer(scr_ticks, tick_time, tick_time);
		}
		else if (k==1)
		{
			print("testing");
			takescreen(heading_deg, pitch_deg);
			setprop("/sim/screenshots/k", 0);
			if (j!=3)
			{
				j=j+1;
				setprop("/sim/screenshots/j", j);
				settimer(scr_ticks, tick_time, tick_time);
			}
			else
			{
				if (i==0)
				{
					i=i+1;
					setprop("/sim/screenshots/i", i);
					j=0;
					setprop("/sim/screenshots/j", j);
					settimer(scr_ticks, tick_time, tick_time);
				}
				else
				{
					setprop("/sim/screenshots/k", 2);
					settimer(scr_ticks, tick_time, tick_time);
				}
			}
		}
		else
		{
			setprop("/sim/menubar/visibility", menubarvalue);
			setprop("/sim/current-view/field-of-view", fovvalue);
			setprop("/sim/current-view/heading-offset-deg", headingvalue);
			setprop("/sim/current-view/pitch-offset-deg", pitchvalue);
			setprop("/sim/freeze/master", freezemvalue);
			setprop("/sim/freeze/clock", freezecvalue);
		}
	}

	setprop("/sim/screenshots/i", 0);
	setprop("/sim/screenshots/j", 0);
	setprop("/sim/screenshots/k", 0);
	scr_ticks();

Also, You would want to comment out next strings at gui.nas file

     if (success) {
         popupTip("Screenshot written to '" ~ path ~ "'", 3);
     } else {
         popupTip("Error writing screenshot '" ~ path ~ "'", 600, button);
     }

by #, to stop that message mess with view.

Now you are ready to start Flightgear but in order to use efficiently this script and the provided Hugin file you need to set the video format to 4/3 (800x600, 1024x768, 1200x900, 1600x1200...). When in the game press the F3 key and wait. You will see the camera changing heading and pitch automatically. When the required screenshots are taken, the original view is restored. Now exit flightgear, look for saved screenshots in png format and follow the next step.

Stitching the panorama with Hugin

Copy all the eight screenshots in a new folder named as you want. Open this folder and create in it a new text file called panorama.pto. Open this file and copy the following lines in it:

# hugin project file
#hugin_ptoversion 2
p f2 w3000 h1500 v360  E0 R0 n"TIFF_m c:LZW r:CROP"
m g1 i0 f0 m2 p0.00784314
 
# image lines
#-hugin  cropFactor=1
i w800 h600 f0 v120 Ra0 Rb0 Rc0 Rd0 Re0 Eev0 Er1 Eb1 r0 p-45 y0 TrX0 TrY0 TrZ0 j0 a0 b0 c0 d0 e0 g0 t0 Va1 Vb0 Vc0 Vd0 Vx0 Vy0  Vm5 u10 n"fgfs-screen-001.png"
#-hugin  cropFactor=1
i w800 h600 f0 v=0 Ra=0 Rb=0 Rc=0 Rd=0 Re=0 Eev0 Er1 Eb1 r0 p-45 y90 TrX0 TrY0 TrZ0 j0 a=0 b=0 c=0 d=0 e=0 g=0 t=0 Va=0 Vb=0 Vc=0 Vd=0 Vx=0 Vy=0  Vm5 u10 n"fgfs-screen-002.png"
#-hugin  cropFactor=1
i w800 h600 f0 v=0 Ra=0 Rb=0 Rc=0 Rd=0 Re=0 Eev0 Er1 Eb1 r0 p-45 y180 TrX0 TrY0 TrZ0 j0 a=0 b=0 c=0 d=0 e=0 g=0 t=0 Va=0 Vb=0 Vc=0 Vd=0 Vx=0 Vy=0  Vm5 u10 n"fgfs-screen-003.png"
#-hugin  cropFactor=1
i w800 h600 f0 v=0 Ra=0 Rb=0 Rc=0 Rd=0 Re=0 Eev0 Er1 Eb1 r0 p-45 y270 TrX0 TrY0 TrZ0 j0 a=0 b=0 c=0 d=0 e=0 g=0 t=0 Va=0 Vb=0 Vc=0 Vd=0 Vx=0 Vy=0  Vm5 u10 n"fgfs-screen-004.png"
#-hugin  cropFactor=1
i w800 h600 f0 v=0 Ra=0 Rb=0 Rc=0 Rd=0 Re=0 Eev0 Er1 Eb1 r0 p45 y0 TrX0 TrY0 TrZ0 j0 a=0 b=0 c=0 d=0 e=0 g=0 t=0 Va=0 Vb=0 Vc=0 Vd=0 Vx=0 Vy=0  Vm5 u10 n"fgfs-screen-005.png"
#-hugin  cropFactor=1
i w800 h600 f0 v=0 Ra=0 Rb=0 Rc=0 Rd=0 Re=0 Eev0 Er1 Eb1 r0 p45 y90 TrX0 TrY0 TrZ0 j0 a=0 b=0 c=0 d=0 e=0 g=0 t=0 Va=0 Vb=0 Vc=0 Vd=0 Vx=0 Vy=0  Vm5 u10 n"fgfs-screen-006.png"
#-hugin  cropFactor=1
i w800 h600 f0 v=0 Ra=0 Rb=0 Rc=0 Rd=0 Re=0 Eev0 Er1 Eb1 r0 p45 y180 TrX0 TrY0 TrZ0 j0 a=0 b=0 c=0 d=0 e=0 g=0 t=0 Va=0 Vb=0 Vc=0 Vd=0 Vx=0 Vy=0  Vm5 u10 n"fgfs-screen-007.png"
#-hugin  cropFactor=1
i w800 h600 f0 v=0 Ra=0 Rb=0 Rc=0 Rd=0 Re=0 Eev0 Er1 Eb1 r0 p45 y270 TrX0 TrY0 TrZ0 j0 a=0 b=0 c=0 d=0 e=0 g=0 t=0 Va=0 Vb=0 Vc=0 Vd=0 Vx=0 Vy=0  Vm5 u10 n"fgfs-screen-008.png"


# specify variables that should be optimized
v r1
v p1
v y1
v r2
v p2
v y2
v r3
v p3
v y3
v r4
v p4
v y4
v r5
v p5
v y5
v r6
v p6
v y6
v r7
v p7
v y7
v 


# control points

#hugin_optimizeReferenceImage 0
#hugin_blender enblend
#hugin_remapper nona
#hugin_enblendOptions 
#hugin_enfuseOptions 
#hugin_hdrmergeOptions -m avg -c
#hugin_outputLDRBlended true
#hugin_outputLDRLayers false
#hugin_outputLDRExposureRemapped false
#hugin_outputLDRExposureLayers false
#hugin_outputLDRExposureBlended false
#hugin_outputLDRExposureLayersFused false
#hugin_outputHDRBlended false
#hugin_outputHDRLayers false
#hugin_outputHDRStacks false
#hugin_outputLayersCompression LZW
#hugin_outputImageType jpg
#hugin_outputImageTypeCompression LZW
#hugin_outputJPEGQuality 100
#hugin_outputImageTypeHDR exr
#hugin_outputImageTypeHDRCompression LZW 

Save the file and open it with Hugin. In Hugin go to the "stitching" tab and press the "Stitch Now" button. You will be asked where to save the resulting image. Select a path and press ok. When Hugin terminates the stitching process you are done. Browse to where you told Hugin to save the panorama, and take a look at the image to check if something went wrong.