Howto:Use a Camera View in an Instrument

From FlightGear wiki
Jump to: navigation, search
IMPORTANT: Some, and possibly most, of the features/ideas discussed here are likely to be affected, and possibly even deprecated, by the ongoing work on providing a property tree-based 2D drawing API accessible from Nasal using the new Canvas system available since FlightGear 2.80 (08/2012). Please see: Canvas Development#Supporting Cameras for further information

You are advised not to start working on anything directly related to this without first discussing/coordinating your ideas with other FlightGear contributors using the FlightGear developers mailing list or the Canvas forum. Anything related to Canvas Core Development should be discussed first of all with TheTom and Zakalawe. Nasal-space frameworks are being maintained by Philosopher and Hooray currently. talk page..

Canvasready.png

Background

Note  There is a related patch available at https://forum.flightgear.org/viewtopic.php?f=71&t=23929#p317448


This was inspired by the ongoing effort to create a realistic 787 for FlightGear, including support for rendering external camera views on instruments: Boeing 787-8 Dreamliner#Camera.2FVideo Surveillance Instrument. The "Tail Camera" is also a feature found on the A380.

Objective

To create a 2D instrument which shows a camera view. Write C++ code, preferably an instrument that renders a Camera View (i.e. from the property tree) to a texture.

The steps involved in creating such an instrument would be:*

  • create a new topic branch: FlightGear and Git#Local_Branch
  • Add a new set of cxx/hxx files to $FG_SRC/Instrumentation/ (e.g. camera-texture.cxx and camera-texture.hxx): to get started quickly, just copy and customize the gyro.* files
  • implement the SGSubsystem interface for the new subsystem [1]
  • add the new files to the CMake build system: Developing using CMake#Adding_new_files_to_the_build
  • add the new subsystem to the instrument_mgr (FGInstrumentMgr::build method)[2]
  • implement the interface for the od_gauge instrument to dynamically create a texture and display update it as a cockpit instrument
  • implement SGPropertyChangeListener to process property tree events and updates [3]
  • Render a property-driven camera view to the created texture (Zan has already code doing this sort of thing [4])
  • Write an XML 2D Instrument file that displays the texture


There are obviously more steps involved here, some of which covered here Howto: Create a 2D drawing API for FlightGear.

Pre-Requisites

The following are required before we continue...

  • To be able to build FlightGear from Source (with or without an IDE)
  • To be able to create new instruments (that would be taking a simple one like gyro, copying it's files and changing the content)
  • A Gitorious account to be able to clone the Flightgear Repository
  • Basic Knowledge of FlightGear and XML

osgViewer::CompositeViewer

This section has been moved to a dedicated article: CompositeViewer Support.

Part 1: Rendering a Camera View to Texture

There're probably many ways to do that, you could do it the way the ground radar instrument does, or how you take a screenshot etc.

A couple nice guides on OpenSceneGraph Rendering are available at:

The OSG Quick Start guide can be download at: http://www.lulu.com/items/volume_51/767000/767629/3/print/OSGQSG.pdf

The OSG API reference is available here: http://www.openscenegraph.org/documentation/OpenSceneGraphReferenceDocs/annotated.html

The OpenSceneGraph Beginners Guide is also available on line.

Also see: http://www.openscenegraph.org/projects/osg/wiki/Support/GettingStarted

The OSG FAQ can be found at: http://www.3drealtimesimulation.com/osg/osg_faq_1.htm

Programming Resources#OSG.2FOpenSceneGraph_related

Screenshot Method

This is a very simple method and is used normally for taking screen-shots.

OpenSceneGraph C++ Code:

osg::Image* shot = new osg::Image();
shot->allocateImage(width, height, 24, GL_RGB, GL_UNSIGNED_BYTE);
camera->attach(osg::Camera::COLOR_BUFFER, shot);
osgDB::writeImageFile(*shot,"image_file.png");

FlightGear code

FlighGear already has an "Owner Drawn instrument" in flightgear/src/Instrumentation/od_gauge.cxx and .hxx (this is now in canvas/simgear). It already sets up a pre-render camera and a texture for it, and has a visitor to replace model's texture with the custom texture.

Using it would be something like this:

  • Create a custom instrument which inherits od_gauge. class CameraInstrument : public FGODGauge { ... }
  • Implement the init and update functions, whatever instrument manager requires.
  • In init set up proper texture sizes and call allocRT().
  • NOTE: od_gauge does NOT add camera to render the scenery, but a custom model. One needs to modify od_gauge so that allocRT calls globals()->get_renderer()->addCamera(camera.get(), true);
  • In update function update camera position according to viewer->getAbsolutePosition(...).
  • Add the custom instrument to instrument_mgr.cxx.

Creating the CamView as a hard coded instrument

Header File: cam_display.hxx

The header file is used to simply initialize a new class that contains all functions related to this instrument. The Functions are just constructed here, the contents are put in the cam_display.cxx file.

// cam_display.hxx - simple function to render view to texture

#ifndef __INSTRUMENTATION_CAMVIEW_HXX
#define __INSTRUMENTATION_CAMVIEW_HXX

#include <simgear/props/props.hxx>
#include "od_gauge.hxx"

class CamView : public SGPropertyChangeListener, public FGODGauge
{
	public:
		static const int TextureHalfSize = 256;
		CamView(SGPropertyNode* node);
		virtual ~CamView();
		void updateTexture();
		virtual void valueChanged(SGPropertyNode*);
		
	protected:
   		void createTexture(const char* texture_name);
		
};

#endif // __INSTRUMENTATION_CAMVIEW_HXX

Adding the Instrument to 'instrument_mgr.cxx'

Your Instrument's header file, cam_display.hxx is a constructor for the main instrument class, and the functions are further defined in the cam_display.cxx function. Include the cam_display.hxx function in the instrument_mgr.cxx file so it knows where your function is.

#include "cam_display.hxx"

In the FGInstrumentMgr::build function, add an else if statement so that it checks whether your instrument too is called.

else if ( name == "cam_display" ) {
            set_subsystem( id, new CamView( node ),1);
        }

Part 2: Getting that texture into an instrument

This part doesn't require any C++ coding, just a simple XML script to use that texture in an instrument.

<?xml version="1.0"?>

<PropertyList>
    <name>Camera Instrument</name>
    <w-base>512</w-base>
    <h-base>512</h-base>

    <layers>
	<layer>
        	<name>camera</name>
            	<texture>
                	<path>image_file.png</path> <!-- Path to the file we just rendered -->
                	<x1>0</x1>
                	<y1>0</y1>
                	<x2>1</x2>
                	<y2>1</y2>
            	</texture>
		<emissive>1</emissive>
        	<w>512</w>
        	<h>512</h>
	</layer>
    </layers>

</PropertyList>

You could create more layers for more cameras/different views or even have a sprite or something on the view. Or we could also add transformations or conditions to the layer to give some function to the instrument other than just show a camera view.

	<transformation>
     		<type>y-shift</type>
     		<property>/instrumentation/camera/y_shift</property>
     		<scale>2</scale>
    	</transformation>

Related