OpenSceneGraph Integration

Often, RotorLib and FixedWingLib developers use OpenSceneGraph for their visualization applications. Below we have summarized a few points which are useful for OSG integrations.

Helicopter/Aircraft Position and Orientation

All helicopter and aircraft models in RTDynamics products are derived from the RTD::VehicleBase class. This class allows querying the current state (position, rotation, etc.) of the vehicle.

  • If you are using a flat earth coordinate system in your OSG application, the methods RTD::VehicleBase::getPosition() or the RTD::VehicleBase::getPositionD()  can be used to get the current position of the aircraft.
  • If you are using a round earth coordinate system (WGS84) in your OSG application, the current geographic coordinates can be queried with the RTD::VehicleBase::getPositionAsLLA() method.
  • There is a utility method which returns the current rotation of the aircraft as a OSG compatible matrix. Internally RTD uses row-major matrices as defined in algebra,however OpenGL applications (e.g. OSG) use column-major matrices. The getRotationGL() returns a rotation matrix in column-major format.

Terrain Queries

RTDynamics helicopters and aircraft simulate ground collisions, loads on landing gears and skids. Additionally terrain following and ground avoidance algorithms in the RotorLib CGF and FixedWingLibCGF require terrain information frequently during simulation.

For this purpose the aircraft must be aware of the terrain. This is made possible by a callback class called TerrainQueryCallback. Developers shall subclass TerrainQueryCallback and re-implement the TerrainQueryCallback::query(). The query() is called by ground contacts periodically with different parameters to get information about the terrain.

A terrain query is a linear intersector between a start and end point. Developers shall construct a line between start and end and intersect it with the terrain to compute information on position, normal and surface velocity at the point of intersection. If there are multiple intersections the nearest one should be returned.

The Simple3d which is shipped with RTDynamics products is a simple OSG application. The source code for the Simple3DTerrainQueryCallback class can be found in the TerrainCallbacks.h file. Below you can see how the query method is implemented.

virtual bool query( const smVec3d& start,
                            const smVec3d& end,
                            smVec3d& hitXYZ ,
                            smVec3d& hitNormal,
                            smVec3d& hitVelocity,
                            smReal& frictionFactor)
{
    // Friction parameter that is defined in the ground contact definition is
    // multiplied with the following value to obtain final friction coefficient.
    // Developers can simulate variousground types (icy, asphalt, soil etc. )
    // using frictionFactor.
    frictionFactor = 1.0f;

    smVec3r tmpXYZ;
    smVec3r tmpNormal;
    if ( m_simple3D->getCollision( start, end , tmpXYZ , tmpNormal ) )
    {
        hitXYZ = tmpXYZ;
        hitNormal = tmpNormal;

        // Terrain does not move so velocity is always zero.
        hitVelocity.set( 0.0 , 0.0 , 0.0 );
        return true; // Since intersector hits the terrain return true.
    }
    return false; // If execution reaches here we do not have a hit. Return false.
}

The Simple3D::getCollision() is implemented as follows using OSG:


bool
Simple3DOSG::getCollision( const smVec3r& sXYZ,
                                         const smVec3r& eXYZ,
                                         smVec3r& contactPos,
                                         smVec3r& contactNormal )
{
    std::vector<osg::Vec3> hitXYZList ;
    std::vector<osg::Vec3> hitNormalList ;
    osg::Vec3 startXYZ = Dina3D::toOSGVec( sXYZ ) ;
    osg::Vec3 endXYZ   = Dina3D::toOSGVec( eXYZ ) ;
    Dina3D::IsectHAT::colTestRay( startXYZ, endXYZ, hitXYZList ,hitNormalList ) ;

    if ( hitXYZList.empty() )
    return false ;

    std::vector<osg::Vec3>::iterator i = hitXYZList.begin () ;
    contactPos.set( (*i)[0], (*i)[1], (*i)[2] ) ;

    i = hitNormalList.begin () ;
    contactNormal.set( (*i)[0], (*i)[1], (*i)[2] ) ;
    return true ;
}

void IsectHAT::colTestRay( const osg::Vec3& startPoint,
                                         const osg::Vec3& endPoint,
                                         std::vector<osg::Vec3>& inHitXYZList ,
                                         std::vector<osg::Vec3>& inHitNormalList  )
{
    // Incoming list is always cleared.
    inHitXYZList.clear() ;
    inHitNormalList.clear() ;

    IntersectVisitor iv( ClassicMasks::All );
    osg::ref_ptr<osg::LineSegment> seg = new osg::LineSegment;

    const osg::BoundingSphere& bs = getScene()->getSceneTopLevelRoot()->getBound();

    seg->set( startPoint, endPoint );
    iv.addLineSegment( seg.get() );

    smManager<osg::LineSegment> segList ;
    segList.add( seg.get() ) ;

    colTestRayCommon( iv, inHitXYZList,inHitNormalList, segList );
}

Animations

Often animating landing gear suspension compression or the control surfaces of an aircraft such the rudder or the flaps is required in 3d visualization applications.

The code required to animate the DOFs on a 3d model is application and 3d model specific.

Again example source code (see AnimationRoutines.h) is available in Simple3D which shows how to acquire landing gear status, control surfaces status and other data which is used for DOF animations.

Below you can see an excerpt from the AnimationRoutines.h file.

	// Here extending/retracting gears is animated. The landing gears and hatch doors have joints.
	// set...GearStatus() receives a value between 0 and 1 which determines how much extended/retracted
	// is the gear. This value is then used to set the joints in the underlying graphics engine.
	a310Animator->setSteeringGearStatus( theAirplane->getGearStatus() );
	a310Animator->setLeftMainGearStatus( theAirplane->getGearStatus() );
	a310Animator->setRightMainGearStatus( theAirplane->getGearStatus() );

	// Animation of the ailerons.
	// set...AileronDeflection makes necessary graphics engine calls to rotate the ailerons.
	{
		float leftAileronAngle = theAirplane->getLeftMainWing()->getControlSurfaceDeflection();
		a310Animator->setLeftAileronDeflection( leftAileronAngle   );

		float rightAileronAngle = theAirplane->getRightMainWing()->getControlSurfaceDeflection();
		a310Animator->setRightAileronDeflection( rightAileronAngle   );
	}

Comments are closed.