VR-Forces 4.10 Class Documentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
exampleProjectile

Table of Contents

Overview

Show how fire a projectile (a Tank!) using the F key and create an explosion

Expected Result

exampleProjectile.png
Projectile over ground Result
exampleProjectile2.png
Projectile over water Result

Example details

This example shows how to fire a projectile from the observer view point. It will also detect if the impact is on ground or water and display the appropriate explosion (smoke or water splash). Currently the projectile type is amplified by using a tank! The commented code is also present to use a more realistic projectile.

Building the Example

VR-Vantage includes pre-built versions of the example plug-in. To build it yourself, follow the instructions at Building VR-Vantage Examples, Applications, and Plug-ins.

Running the Example

This example is a plug-in. You can run it by running ./bin64/exampleProjectile_stealth.bat (on Windows) or ./bin64/exampleProjectile_stealth (on Linux). Press 'f' to fire the projectile. For more information about running examples, please see Running Applications and Examples.

Example Source Files


DtExampleProjectile.cxx

/*****************************************************************************
* Copyright (c) 2020 MAK Technologies, Inc.
* All rights reserved.
*****************************************************************************/
#include <vrvCore/DtDe.h>
// For detonation
#include <vrvCore/DtSceneObjectAgent.hpp>
#include <vrvCore/DtParticleSystemModelAgent.hpp>
#include <vrvCore/DtWaterImpactModelAgent.hpp>
// For observer test
#include <vrvCore/DtOverlaySegmentedLineModelAgent.hpp>
// Use the VR-Vantage namespace.
// All classes in VR-Vantage are in this namespace.
namespace makVrv
{
: makVrv::DtDriver( am, "DtExampleProjectile" )
, myObserverShooter( 0 )
{
}
DtExampleProjectile::~DtExampleProjectile()
{
DtExampleProjectile::onStop();
}
const std::string& DtExampleProjectile::className() const
{
static std::string name = "DtExampleProjectile";
return name;
}
bool DtExampleProjectile::onStart()
{
// Load Makland programatically.
DtScene& sceneDriver = myAgentManager.de().scene();
std::string maklandPath = myAgentManager.de().dePathConfiguration().userPath();
maklandPath += "/terrains/Makland.mtf";
if ( sceneDriver.terrainFileName() != maklandPath )
{
sceneDriver.loadTerrain( maklandPath );
}
myObserverShooter = new DtObserverShooter( myAgentManager.de() );
// Something realistic
//myObserverShooter->setProjectileSpeed( 914. );
// Make is easy to see
myObserverShooter->setModelDefinitionName( "TrackedM1Abrams" );
myObserverShooter->setProjectileSpeed( 100. );
myObserverShooter->setIntersectionCallback(
boost::bind( &DtExampleProjectile::processIntersection, this, _1, _2 ) );
return true;
}
bool DtExampleProjectile::onStop()
{
if ( myObserverShooter )
{
delete myObserverShooter;
myObserverShooter = 0;
}
// Clean up any leftover detonations / splashes
DetonationList::const_iterator detIter = myDetonationObjects.begin();
DetonationList::const_iterator endDetIter = myDetonationObjects.end();
for( ; detIter != endDetIter; ++detIter )
{
if ( ! myAgentManager.de().destructing() )
{
DetonationData detonation = *detIter;
detonation.detonationObject->removeModel( detonation.detonationModel );
delete detonation.detonationModel;
delete detonation.detonationObject;
}
}
myDetonationObjects.clear();
SplashList::const_iterator splashIter = mySplashObjects.begin();
SplashList::const_iterator endSplashIter = mySplashObjects.end();
for( ; splashIter != endSplashIter; ++splashIter )
{
if ( ! myAgentManager.de().destructing() )
{
SplashData splash = *splashIter;
splash.splashObject->removeModel( splash.splashModel );
delete splash.splashModel;
delete splash.splashObject;
}
}
mySplashObjects.clear();
return true;
}
bool DtExampleProjectile::onTick()
{
if ( myObserverShooter )
{
myObserverShooter->tick( myAgentManager.de().simulationTime() );
}
return true;
}
void DtExampleProjectile::slot_displayEngineAdded( const DtDeRecord& igRecord )
{
stop();
start();
}
void DtExampleProjectile::processIntersection( const DtIntersectorResult& isectResult, double speed )
{
std::cout << "Hit: "<< isectResult.x << " " << isectResult.y << " " << isectResult.z;
if ( isectResult.dynamicOcean )
{
createSplash( DtVector( isectResult.x, isectResult.y, isectResult.z ), speed );
std::cout << " Type: " << "Ocean" << std::endl;
}
else
{
DtElementEntry* entry = myAgentManager.de().dataBank().elementData().findElement( isectResult.id );
if ( entry )
{
switch( entry->type() )
{
createDetonation( DtVector( isectResult.x, isectResult.y, isectResult.z ) );
std::cout << " Type: " << "Entity" << std::endl;
break;
createDetonation( DtVector( isectResult.x, isectResult.y, isectResult.z ) );
std::cout << " Type: " << "Prop" << std::endl;
break;
case DtElementEntry::TerrainPatch:
createDetonation( DtVector( isectResult.x, isectResult.y, isectResult.z ) );
std::cout << " Type: " << "Terrain" << std::endl;
break;
default:
std::cout << " Type: " << entry->type() << std::endl;
break;
}
}
else
{
std::cout << " Type: Unregistered Object" << std::endl;
}
}
}
void DtExampleProjectile::createDetonation( const DtVector& position )
{
DtSceneObjectAgent* sceneObj = DtSceneObjectAgent::create( myAgentManager );
sceneObj->setModelSet( DtObserverMode::ModelSet3dModels );
sceneObj->setPosition( 0, DtVector( position ) );
DtParticleSystemModelAgent* detonation = DtParticleSystemModelAgent::create( myAgentManager );
sceneObj->addModel( detonation, 0 );
detonation->setModelDefinition( "DetonationBombBlastLarge" );
DetonationData data;
data.detonationObject = sceneObj;
data.detonationModel = detonation;
data.timeOfOccurence = myAgentManager.de().simulationTime();
myDetonationObjects.push_back( data );
}
void DtExampleProjectile::createSplash( const DtVector& position, double speed )
{
DtSceneObjectAgent* sceneObj = DtSceneObjectAgent::create( myAgentManager );
sceneObj->setModelSet( DtObserverMode::ModelSet3dModels );
//sceneObj->setPosition( 0, DtVector( position ) );
DtWaterImpactModelAgent* splash = DtWaterImpactModelAgent::create( myAgentManager );
sceneObj->addModel( splash, 0 );
splash->setModelDefinition( "DetonationWaterImpactExtraLarge" );
splash->setImpactLocation( position );
splash->setMunitionSpeed( speed );
SplashData data;
data.splashObject = sceneObj;
data.splashModel = splash;
data.timeOfOccurence = myAgentManager.de().simulationTime();
mySplashObjects.push_back( data );
}
}

DtExampleProjectile.h

/*****************************************************************************
* Copyright (c) 2019 MAK Technologies, Inc.
* All rights reserved.
*****************************************************************************/
#pragma once
#include <matrix/vlVector.h>
#include <string>
#include <list>
namespace makVrv
{
class DtObserverShooter;
class DtIntersectorResult;
class DtSceneObjectAgent;
class DtParticleSystemModelAgent;
class DtWaterImpactModelAgent;
class DT_DLL_EXAMPLEPROJECTILE DtExampleProjectile : public makVrv::DtDriver
{
public:
DtExampleProjectile( makVrv::DtAgentManager& am );
virtual ~DtExampleProjectile();
virtual const std::string& className() const;
protected:
virtual bool onStart();
virtual bool onStop();
virtual bool onTick();
virtual void slot_displayEngineAdded( const makVrv::DtDeRecord& igRecord );
virtual void processIntersection( const DtIntersectorResult& isect, double speed );
virtual void createDetonation( const DtVector& position );
virtual void createSplash( const DtVector& position, double speed );
protected:
DtObserverShooter* myObserverShooter;
struct DetonationData
{
DtSceneObjectAgent* detonationObject;
DtParticleSystemModelAgent* detonationModel;
double timeOfOccurence;
};
struct SplashData
{
DtSceneObjectAgent* splashObject;
DtWaterImpactModelAgent* splashModel;
double timeOfOccurence;
};
typedef std::list<DetonationData> DetonationList;
typedef std::list<SplashData> SplashList;
DetonationList myDetonationObjects;
SplashList mySplashObjects;
};
}

DtObserverShooter.cxx

/*****************************************************************************
* Copyright (c) 2019 MAK Technologies, Inc.
* All rights reserved.
*****************************************************************************/
#include <vrvCore/DtDe.h>
#include <osg/Matrixd>
// Use the VR-Vantage namespace.
// All classes in VR-Vantage are in this namespace.
namespace makVrv
{
: myDe( de )
, myModelDefinitionName( "" )
, myProjectileSpeed( 100. ) // m/s
, myExpiredProjectiles()
, myIntersectionCallback( (DtProjectile::IntersectionCallback) 0 )
{
DtInputDriver& inputDriver = de.driverManager().inputDriver();
DtKeyMapManager& keyMapManager = DtKeyMapManager::instance(de);
//Create key functions for toggling sensor effects options on and off
keyMapManager.addKeyFunction( "Fire Projectile", boost::bind(
&DtObserverShooter::fireProjectile, this), DtKeyMapManager::Miscellaneous);
DtKeyMap* obsFrame = keyMapManager.findKeyMap( "Observer Frame" );
if ( obsFrame )
{
//map functions for modifing the size and animation rate of the cubes.
inputDriver.addKeyBinding( obsFrame, DtKeyState::KEY_F, "Fire Projectile" ,
DtKeyState::NO_MODIFIER, true);
}
}
DtObserverShooter::~DtObserverShooter()
{
ProjectileMap::iterator curIter = myProjectiles.begin();
ProjectileMap::iterator endIter = myProjectiles.end();
for( ; curIter != endIter; ++curIter )
{
delete curIter->second;
}
myProjectiles.clear();
DtKeyMapManager& keyMapManager = DtKeyMapManager::instance( myDe );
keyMapManager.removeKeyFunction( "Fire Projectile" );
}
void DtObserverShooter::fireProjectile()
{
DtObserver* obs = myDe.driverManager().inputDriver().findObserverByName( "Observer 1" );
if ( obs )
{
DtVector start = obs->location();
double yaw, pitch, roll;
obs->getOrientation( yaw, pitch, roll );
DtTaitBryan orientation( -yaw, pitch, roll );
DtVector direction = obs->observerCameraFront();
DtProjectile* proj = new DtProjectile( myDe, start, orientation, myProjectileSpeed, direction,
myModelDefinitionName, myIntersectionCallback );
myProjectiles[proj->id()] = proj;
}
}
void DtObserverShooter::setModelDefinitionName( const std::string& modelDefinitionName )
{
myModelDefinitionName = modelDefinitionName;
}
void DtObserverShooter::setProjectileSpeed( double speed )
{
myProjectileSpeed = speed;
}
void DtObserverShooter::setIntersectionCallback( DtProjectile::IntersectionCallback callback )
{
myIntersectionCallback = callback;
}
void DtObserverShooter::removeExpiredProjectiles()
{
std::list<ProjectileMap::iterator> removeList;
ProjectileIDList::iterator curIter = myExpiredProjectiles.begin();
ProjectileIDList::iterator endIter = myExpiredProjectiles.end();
for( ; curIter != endIter; ++curIter )
{
DtUniqueID projectile = *curIter;
ProjectileMap::iterator findIter = myProjectiles.find( projectile );
if ( findIter != myProjectiles.end() )
{
delete findIter->second;
removeList.push_back( findIter );
}
}
std::list<ProjectileMap::iterator>::iterator delIter = removeList.begin();
std::list<ProjectileMap::iterator>::iterator endDelIter = removeList.end();
for ( ; delIter != endDelIter; ++delIter )
{
myProjectiles.erase( *delIter );
}
}
void DtObserverShooter::tick( double simTime )
{
removeExpiredProjectiles();
ProjectileMap::iterator curIter = myProjectiles.begin();
ProjectileMap::iterator endIter = myProjectiles.end();
for( ; curIter != endIter; ++curIter )
{
if ( ! curIter->second->tick( simTime ) )
{
myExpiredProjectiles.push_back( curIter->first );
}
}
}
}

DtObserverShooter.h

/*****************************************************************************
** Copyright (c) 2019 MAK Technologies, Inc.
** All rights reserved.
*****************************************************************************/
#pragma once
#include "DtProjectile.h"
#include <matrix/vlVector.h>
#include <matrix/vlTaitBryan.h>
#include <boost/unordered_map.hpp>
#include <boost/function.hpp>
#include <list>
#include <string>
// Use the VR-Vantage namespace.
// All classes in VR-Vantage are in this namespace.
namespace makVrv
{
class DtDe;
class DT_DLL_EXAMPLEPROJECTILE DtObserverShooter
{
public:
DtObserverShooter( DtDe& de );
virtual ~DtObserverShooter();
void fireProjectile();
void setModelDefinitionName( const std::string& modelDefinitionName );
void setProjectileSpeed( double speed );
void tick( double simTime );
void removeExpiredProjectiles();
void setIntersectionCallback( DtProjectile::IntersectionCallback callback );
protected:
typedef boost::unordered_map<DtUniqueID, DtProjectile*> ProjectileMap;
typedef std::list<DtUniqueID> ProjectileIDList;
protected:
DtDe& myDe;
ProjectileMap myProjectiles;
ProjectileIDList myExpiredProjectiles;
std::string myModelDefinitionName;
double myProjectileSpeed;
DtProjectile::IntersectionCallback myIntersectionCallback;
};
}

DtProjectile.cxx

/*****************************************************************************
* Copyright (c) 2019 MAK Technologies, Inc.
* All rights reserved.
*****************************************************************************/
#include <DtProjectile.h>
#include <vrvCore/DtDe.h>
#include <vrvCore/DtSceneObjectAgent.hpp>
#include <osg/Matrixd>
// Use the VR-Vantage namespace.
// All classes in VR-Vantage are in this namespace.
namespace makVrv
{
DtProjectile::DtProjectile(DtDe& de, const DtVector& start, const DtTaitBryan& orientation, double speed,
const DtVector& direction, const std::string& modelDefinitionName, IntersectionCallback callback )
: myDe( de )
, myFiringPosition( start )
, myFiringStartTime( -1. )
, myIntersectionCallback( callback )
{
DtUniqueID elementId = myDe.agentManager().createNewUniqueId();
myFacade = new DtEntity3dFacade( myDe.agentManager(),
DtSharedSettingsManager::instance( myDe ), elementId, 0, true );
myFacade->setUpdateTypes( false, false );
myFacade->setArticulatedModelDefinition( modelDefinitionName );
myFacade->setPosition( start );
myFacade->setOrientation( orientation );
myFacade->setVisible( true );
DtVecScale( direction, speed, myVelocity0 );
myDe.sharedState().coordinateSystem().converter()->setupTopoFrame( start );
DtVecScale( myDe.sharedState().coordinateSystem().converter()->up( start ), -9.81, myAcceleration );
}
DtProjectile::~DtProjectile()
{
delete myFacade;
myFacade = 0;
}
bool DtProjectile::tick( double simTime )
{
if ( myFiringStartTime < 0. )
{
myFiringStartTime = simTime;
return true;
}
double total_time = simTime - myFiringStartTime;
DtVector newPos;
// P = P0 + v0t + 1/2at(2)
DtVector vComponent;
DtVecScale( myVelocity0, total_time, vComponent );
DtVector aComponent;
double oneHalf_tSquared = ( total_time * total_time) / 2. ;
DtVecScale( myAcceleration, oneHalf_tSquared, aComponent );
newPos = myFiringPosition + vComponent + aComponent;
DtIntersector& intersector = DtIntersectorManager::instance(myDe).modelSetIntersector( 0 );
DtIntersectorResult isectResult;
std::vector<DtElementID> ignoreList;
ignoreList.push_back( id() );
DtVector pos = myFacade->position();
bool hit = intersector.findFirstIntersectWithLineSegment( pos.x(), pos.y(), pos.z(),
newPos.x(), newPos.y(), newPos.z(), isectResult, DtIntersector::PickableNodes, &ignoreList );
if ( hit )
{
newPos = DtVector( isectResult.x, isectResult.y, isectResult.z );
if ( myIntersectionCallback )
{
// V = V0 + at
DtVecScale( myAcceleration, total_time, aComponent );
DtVector velocity = myVelocity0 + aComponent;
myIntersectionCallback( isectResult, sqrt( velocity.magnitudeSquared() ) );
}
myFacade->setOrientation( orientationFromOldAndNewPositions( myFacade->position(), newPos ) );
myFacade->setPosition( newPos );
return false; // delete next frame
}
myFacade->setOrientation( orientationFromOldAndNewPositions( myFacade->position(), newPos ) );
myFacade->setPosition( newPos );
return true; // continue to process
}
DtUniqueID DtProjectile::id() const
{
if ( myFacade )
{
return myFacade->elementId();
}
return (DtUniqueID)0;
}
DtTaitBryan DtProjectile::orientationFromOldAndNewPositions(const DtVector& oldPos, const DtVector& newPos )
{
// DtOrientToVector expects Geocentric positions. These calls will be just vector copies
// if using geocentric coordinates
DtVector geoStart, geoEnd;
DtCoordinateSystem& coordSys = myDe.sharedState().coordinateSystem();
coordSys.localToNetPos( oldPos, geoStart );
coordSys.localToNetPos( newPos, geoEnd );
DtQuat qOri = DtOrientToVector( *(coordSys.converter()), geoStart, geoEnd );
double yaw, pitch, roll;
DtQuaternionToEulerRad(qOri.xyz.x(), qOri.xyz.y(), qOri.xyz.z(), qOri.w, yaw, pitch, roll);
return DtTaitBryan( yaw, pitch, roll );
}
}

DtProjectile.cxx

/*****************************************************************************
* Copyright (c) 2019 MAK Technologies, Inc.
* All rights reserved.
*****************************************************************************/
#include <DtProjectile.h>
#include <vrvCore/DtDe.h>
#include <vrvCore/DtSceneObjectAgent.hpp>
#include <osg/Matrixd>
// Use the VR-Vantage namespace.
// All classes in VR-Vantage are in this namespace.
namespace makVrv
{
DtProjectile::DtProjectile(DtDe& de, const DtVector& start, const DtTaitBryan& orientation, double speed,
const DtVector& direction, const std::string& modelDefinitionName, IntersectionCallback callback )
: myDe( de )
, myFiringPosition( start )
, myFiringStartTime( -1. )
, myIntersectionCallback( callback )
{
DtUniqueID elementId = myDe.agentManager().createNewUniqueId();
myFacade = new DtEntity3dFacade( myDe.agentManager(),
DtSharedSettingsManager::instance( myDe ), elementId, 0, true );
myFacade->setUpdateTypes( false, false );
myFacade->setArticulatedModelDefinition( modelDefinitionName );
myFacade->setPosition( start );
myFacade->setOrientation( orientation );
myFacade->setVisible( true );
DtVecScale( direction, speed, myVelocity0 );
myDe.sharedState().coordinateSystem().converter()->setupTopoFrame( start );
DtVecScale( myDe.sharedState().coordinateSystem().converter()->up( start ), -9.81, myAcceleration );
}
DtProjectile::~DtProjectile()
{
delete myFacade;
myFacade = 0;
}
bool DtProjectile::tick( double simTime )
{
if ( myFiringStartTime < 0. )
{
myFiringStartTime = simTime;
return true;
}
double total_time = simTime - myFiringStartTime;
DtVector newPos;
// P = P0 + v0t + 1/2at(2)
DtVector vComponent;
DtVecScale( myVelocity0, total_time, vComponent );
DtVector aComponent;
double oneHalf_tSquared = ( total_time * total_time) / 2. ;
DtVecScale( myAcceleration, oneHalf_tSquared, aComponent );
newPos = myFiringPosition + vComponent + aComponent;
DtIntersector& intersector = DtIntersectorManager::instance(myDe).modelSetIntersector( 0 );
DtIntersectorResult isectResult;
std::vector<DtElementID> ignoreList;
ignoreList.push_back( id() );
DtVector pos = myFacade->position();
bool hit = intersector.findFirstIntersectWithLineSegment( pos.x(), pos.y(), pos.z(),
newPos.x(), newPos.y(), newPos.z(), isectResult, DtIntersector::PickableNodes, &ignoreList );
if ( hit )
{
newPos = DtVector( isectResult.x, isectResult.y, isectResult.z );
if ( myIntersectionCallback )
{
// V = V0 + at
DtVecScale( myAcceleration, total_time, aComponent );
DtVector velocity = myVelocity0 + aComponent;
myIntersectionCallback( isectResult, sqrt( velocity.magnitudeSquared() ) );
}
myFacade->setOrientation( orientationFromOldAndNewPositions( myFacade->position(), newPos ) );
myFacade->setPosition( newPos );
return false; // delete next frame
}
myFacade->setOrientation( orientationFromOldAndNewPositions( myFacade->position(), newPos ) );
myFacade->setPosition( newPos );
return true; // continue to process
}
DtUniqueID DtProjectile::id() const
{
if ( myFacade )
{
return myFacade->elementId();
}
return (DtUniqueID)0;
}
DtTaitBryan DtProjectile::orientationFromOldAndNewPositions(const DtVector& oldPos, const DtVector& newPos )
{
// DtOrientToVector expects Geocentric positions. These calls will be just vector copies
// if using geocentric coordinates
DtVector geoStart, geoEnd;
DtCoordinateSystem& coordSys = myDe.sharedState().coordinateSystem();
coordSys.localToNetPos( oldPos, geoStart );
coordSys.localToNetPos( newPos, geoEnd );
DtQuat qOri = DtOrientToVector( *(coordSys.converter()), geoStart, geoEnd );
double yaw, pitch, roll;
DtQuaternionToEulerRad(qOri.xyz.x(), qOri.xyz.y(), qOri.xyz.z(), qOri.w, yaw, pitch, roll);
return DtTaitBryan( yaw, pitch, roll );
}
}

exampleProjectile.cxx

/*****************************************************************************
* Copyright (c) 2019 MAK Technologies, Inc.
* All rights reserved.
*****************************************************************************/
#include <vrvCore/DtDe.h>
void postPluginTransform(makVrv::DtDeInitializer& initializer, makVrv::DtDe& de, makVrv::DtVrvApplicationConfiguration& appConfig)
{
// Make sure that the vrvCoreQt and vrvOsgEarthQt module are init'ed.
// Don't show the startup dialog for selecting a terrain.
makVrv::DtQtDeMainWindow& mainWindow = dynamic_cast<makVrv::DtQtDeMainWindow&>(mw);
mainWindow.hideStartupDialog();
}
{
// The driver is now owned by the display engine. Do not delete it.
de.driverManager().addDriver(driver);
// Start the driver, creating the agent.
de.driverManager().startDriver(driver);
}
void init(makVrv::DtDe& de)
{
// Ensure that init only gets called once
// (not strictly necessary here, but this is good practice in general)
// We only want to create the driver if we are running in master mode.
if (de.isInMasterMode())
{
// Create a functor to install into the application.
makVrv::DtVrvApplication::ApplicationTransform functor = boost::bind(&postPluginTransform, _1, _2, _3);
// Install our application transform to execute after the plug-ins are loaded and before the
// GUI is assembled.
igApp->installPostPluginTransform(functor, "postPluginTransform");
// The accessory must be created after the DE's initialization is
// finished, to make sure all the objects it uses exist.
&installDriver, boost::ref(de)));
}
}
{
// Setup the plug-in. Normally, the init function and functionality
// should be in its own library.
init(*de);
return true;
}

[<< Examples] [Home] [Top of Page]


Document ID: Generated on Tue Sep 21 17:42:52 EDT 2021 from SVN revision 234861
Copyright © 2005-2021 MAK Technologies. All Rights Reserved (www.mak.com)