当前位置:网站首页>Osgearth target selection
Osgearth target selection
2022-07-03 08:19:00 【CHPCWWHSU】
osgEarth Target pickup
This article shows a method of target selection . By way of osg::Node Sign up to osgEarth In the object manager , utilize osgEarth Of RTTPicker Class and overridden RTTPicker::Callback class , The selection of achieving goals , The use of osgEarth::VirtualProgram class , Highlight the picked object .
This paper mainly solves the following problems :
- osgEarth::RTTPicker Achieve target pickup
- RTTPicker::Callback Callback parsing
- osgEarth::VirtualProgram The target highlights
Catalog
- 1 Preface
- 2 osgEarth::RTTPicker And RTTPicker::Callback Achieve target pickup
- 3 osgEarth::VirtualProgram The target highlights
Content
- 1 Preface
osgEarth Mouse picking operations such as middle annotations are different from ordinary collision detection picking ,PlaceNode And other annotation types are not rendered in the usual scene space , It is rendered as a superimposed layer of screen space , The object of intersection cannot be obtained through collision detection .
osgEarth There is an example of Sample osgearth_pick, Demonstrated how to pass through RTTPicker Technology realizes the selection of objects in the scene . Vectors and annotations added to the scene can be picked up with the mouse , But for ordinary model data, we can't get . You can register , Will be added to the scene osg::Node To register ,osgEarth in ObjectIndex Class manages the registration of objects , It provides an interface for adding osg::Node To register .
- 2 osgEarth::RTTPicker And RTTPicker::Callback Achieve target pickup
First osgEarth analysis .earth File to build the scene , There can be terrain in the scene 、 image 、 vector 、 Data such as models , This article mainly realizes the pickup of model data ; Then register the picked nodes ; Then the mouse picks up the target .
From the outside earth File import node :
<Map name="Demo: simple model layer">
<Model name="Cow in the Hudson">
<url>C:/Geoway/SVN/gwEarth/trunk/osgearth/data/streetlight.osgb.(0,0,3.14).trans.100.scale</url>
<location lat="40.717" long="-74.018"/>
</Model>
<viewpoints>
<viewpoint name="Test" heading="0" lat="40.717" long="-74.018" height="1500" pitch="-90" range="1500" />
</viewpoints>
</Map>
As above .earth Contents of the file , There are two parts : Model layer and viewpoint layer . The model layer adopts Model keyword , among url The field represents the location path of the model ,location The field represents the position of the ball on the model and viewpoints Layers ; Viewpoint layer is used viewpoints Keyword to represent , It contains name、heading、lat、long、height、pitch and range Seven parameters , Respectively represent the layer name 、 azimuth 、 Location latitude 、 longitude 、 Height 、 Pitch angle 、 Range .
ui::VBox* uiContainer = new ui::VBox();
uiContainer->setAlign( ui::Control::ALIGN_LEFT, ui::Control::ALIGN_TOP );
uiContainer->setAbsorbEvents( true );
uiContainer->setBackColor(0,0,0,0.8);
uiContainer->addControl( new ui::LabelControl("RTT Picker Test", osg::Vec4(1,1,0,1)) );
uiContainer->addControl( new ui::ButtonControl("Toggle picker", new TogglePicker(app)) );
app.fidLabel = new ui::LabelControl("---");
uiContainer->addControl( app.fidLabel );
app.nameLabel = uiContainer->addControl( new ui::LabelControl( "---" ) );
// Load up the earth file.
osg::Node* node = MapNodeHelper().load( arguments, &app.viewer, uiContainer );
Code segment 2 From the outside earth File import results in osg::Node Code for , Got osg::Node Contains two child nodes , Respectively MapNode and Controls::ControlCanvas, ControlCanvas Contains four LabelControl And a ButtonControl, Used to control the opening and closing of object picking , And the display of object information .
Next, turn on the target picking function , At the same time, realize the registration of objects :
struct App
{
App(osg::ArgumentParser& args) : viewer(args), mainView(NULL),
mapNode(NULL), picker(NULL), fidLabel(NULL),
nameLabel(NULL), highlightUniform(NULL)
{ }
osgViewer::CompositeViewer viewer;
osgViewer::View* mainView;
osgEarth::MapNode* mapNode;
osgEarth::Util::RTTPicker* picker;
ui::LabelControl* fidLabel;
ui::LabelControl* nameLabel;
osg::Uniform* highlightUniform;
};
void startPicker(App& app)
{
// Note! Must stop and restart threading when removing the picker
// because it changes the OSG View/Slave configuration.
app.viewer.stopThreading();
app.picker = new RTTPicker();
app.mainView->addEventHandler(app.picker);
ResistryNodeVisitor rn;
app.mapNode->accept(rn);
// add the graph that will be picked.
app.picker->addChild(app.mapNode);
// install a callback that controls the picker and listens for hits.
app.picker->setDefaultCallback(new MyPickCallback(app));
app.viewer.startThreading();
}
Code segment 1 It is a structure , It mainly includes a view 、 Main view 、MapNode as well as Util::RTTPicker; Code segment 2 To enable node picking ,RTTPicker Inherited from osgGA::GUIEventHandler, You can add it directly to the view as an event ;ResistryNodeVisitor For an accessor , Realize the registration of nodes , Its core code is :osgEarth::Registry::objectIndex()->tagNode(&node, &node); tageNode The English interpretation of :
/**
* Inserts the object into the index, and tags the Node with a uniform containing
* the object id. Returns the Object ID.
*/
About an object ( The second parameter ) Insert into index In the table , At the same time One osg::Uniform Object is written to the node ( The first parameter ).
The last set RTTPicker Of CallBack.RTTPicker Class inherits from osgGA::GUIEventHandler, It rewrites handle function ,handle Called in the function runPicks function ,runPicks Called checkForPickResult function ,checkForPickResult The function is called RTTPlicker::CallBack Medium onHit function , This article rewrites RTTPicker::CallBack Medium onHit() Function to achieve the acquisition of picked objects :
struct MyPickCallback : public RTTPicker::Callback
{
App& _app;
MyPickCallback(App& app) : _app(app) { }
void onHit(ObjectID id)
{
// First see whether it's a feature:
FeatureIndex* index = Registry::objectIndex()->get<FeatureIndex>(id).get();
Feature* feature = index ? index->getFeature( id ) : 0L;
if ( feature )
{
_app.fidLabel->setText( Stringify() << "Feature ID = " << feature->getFID() << " (oid = " << id << ")" );
_app.nameLabel->setText( Stringify() << "Name = " << feature->getString("name") );
}
else
{
// Check whether it's an annotation:
AnnotationNode* anno = Registry::objectIndex()->get<AnnotationNode>(id).get();
if ( anno )
{
_app.fidLabel->setText( Stringify() << "ObjectID = " << id );
_app.nameLabel->setName( Stringify() << "Name = " << anno->getName() );
}
// None of the above.. clear.
else
{
_app.fidLabel->setText( Stringify() << "unknown oid = " << id );
_app.nameLabel->setText( " " );
}
}
_app.highlightUniform->set( id );
}
void onMiss()
{
_app.fidLabel->setText( "No pick." );
_app.nameLabel->setText( " " );
_app.highlightUniform->set( 0u );
}
// pick whenever the mouse moves.
bool accept(const osgGA::GUIEventAdapter& ea, const osgGA::GUIActionAdapter& aa)
{
return ea.getEventType() == ea.PUSH;
}
};
among onHit Function by objectId Get the corresponding node , Finally, set the highlighted node to the corresponding id(_app.highlightUniform->set( id )).
3 osgEarth::VirtualProgram The target highlights
const char* highlightVert =
"#version " GLSL_VERSION_STR "\n"
"uniform uint objectid_to_highlight; \n"
"uint oe_index_objectid; // Stage global containing object id \n"
"flat out int selected; \n"
"void checkForHighlight(inout vec4 vertex) \n"
"{ \n"
" selected = (objectid_to_highlight > 1u && objectid_to_highlight == oe_index_objectid) ? 1 : 0; \n"
"} \n";
const char* highlightFrag =
"#version " GLSL_VERSION_STR "\n"
"flat in int selected; \n"
"void highlightFragment(inout vec4 color) \n"
"{ \n"
" if ( selected == 1 ) \n"
" color.rgb = mix(color.rgb, clamp(vec3(0.5,2.0,2.0)*(1.0-color.rgb), 0.0, 1.0), 0.5); \n"
"} \n";
void installHighlighter(App& app)
{
osg::StateSet* stateSet = app.mapNode->getOrCreateStateSet();
int attrLocation = Registry::objectIndex()->getObjectIDAttribLocation();
// This shader program will highlight the selected object.
VirtualProgram* vp = VirtualProgram::getOrCreate(stateSet);
vp->setFunction( "checkForHighlight", highlightVert, ShaderComp::LOCATION_VERTEX_CLIP );
vp->setFunction( "highlightFragment", highlightFrag, ShaderComp::LOCATION_FRAGMENT_COLORING );
// Since we're accessing object IDs, we need to load the indexing shader as well:
Registry::objectIndex()->loadShaders( vp );
// A uniform that will tell the shader which object to highlight:
app.highlightUniform = new osg::Uniform("objectid_to_highlight", 0u);
stateSet->addUniform(app.highlightUniform );
}
adopt VirtualProgram Set node shaders and slice shaders , To achieve specific ID The node of , Highlight .
Finally, the complete code is as follows :
/* -*-c++-*- */
/* osgEarth - Geospatial SDK for OpenSceneGraph
* Copyright 2020 Pelican Mapping
* http://osgearth.org
*
* osgEarth is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
#include <osgEarth/Registry>
#include <osgEarth/ShaderGenerator>
#include <osgEarth/ObjectIndex>
#include <osgEarth/GLUtils>
#include <osgEarth/EarthManipulator>
#include <osgEarth/ExampleResources>
#include <osgEarth/Controls>
#include <osgEarth/RTTPicker>
#include <osgEarth/Feature>
#include <osgEarth/FeatureIndex>
#include <osgEarth/AnnotationNode>
#include <osgEarth/IntersectionPicker>
#include <osgViewer/CompositeViewer>
#include <osgGA/TrackballManipulator>
#include <osg/BlendFunc>
#define LC "[rttpicker] "
using namespace osgEarth;
using namespace osgEarth::Util;
namespace ui = osgEarth::Util::Controls;
//-----------------------------------------------------------------------
//! Application-wide data.
struct App
{
App(osg::ArgumentParser& args) : viewer(args), mainView(NULL),
mapNode(NULL), picker(NULL), fidLabel(NULL),
nameLabel(NULL), highlightUniform(NULL)
{ }
osgViewer::CompositeViewer viewer;
osgViewer::View* mainView;
osgEarth::MapNode* mapNode;
osgEarth::Util::RTTPicker* picker;
ui::LabelControl* fidLabel;
ui::LabelControl* nameLabel;
osg::Uniform* highlightUniform;
};
//! Callback that you install on the RTTPicker.
struct MyPickCallback : public RTTPicker::Callback
{
App& _app;
MyPickCallback(App& app) : _app(app) { }
void onHit(ObjectID id)
{
// First see whether it's a feature:
FeatureIndex* index = Registry::objectIndex()->get<FeatureIndex>(id).get();
Feature* feature = index ? index->getFeature( id ) : 0L;
if ( feature )
{
_app.fidLabel->setText( Stringify() << "Feature ID = " << feature->getFID() << " (oid = " << id << ")" );
_app.nameLabel->setText( Stringify() << "Name = " << feature->getString("name") );
}
else
{
// Check whether it's an annotation:
AnnotationNode* anno = Registry::objectIndex()->get<AnnotationNode>(id).get();
if ( anno )
{
_app.fidLabel->setText( Stringify() << "ObjectID = " << id );
_app.nameLabel->setName( Stringify() << "Name = " << anno->getName() );
}
// None of the above.. clear.
else
{
_app.fidLabel->setText( Stringify() << "unknown oid = " << id );
_app.nameLabel->setText( " " );
}
}
_app.highlightUniform->set( id );
}
void onMiss()
{
_app.fidLabel->setText( "No pick." );
_app.nameLabel->setText( " " );
_app.highlightUniform->set( 0u );
}
// pick whenever the mouse moves.
bool accept(const osgGA::GUIEventAdapter& ea, const osgGA::GUIActionAdapter& aa)
{
return ea.getEventType() == ea.PUSH;
}
};
//-----------------------------------------------------------------------
// Shaders that will highlight the currently "picked" feature.
const char* highlightVert =
"#version " GLSL_VERSION_STR "\n"
"uniform uint objectid_to_highlight; \n"
"uint oe_index_objectid; // Stage global containing object id \n"
"flat out int selected; \n"
"void checkForHighlight(inout vec4 vertex) \n"
"{ \n"
" selected = (objectid_to_highlight > 1u && objectid_to_highlight == oe_index_objectid) ? 1 : 0; \n"
"} \n";
const char* highlightFrag =
"#version " GLSL_VERSION_STR "\n"
"flat in int selected; \n"
"void highlightFragment(inout vec4 color) \n"
"{ \n"
" if ( selected == 1 ) \n"
" color.rgb = mix(color.rgb, clamp(vec3(0.5,2.0,2.0)*(1.0-color.rgb), 0.0, 1.0), 0.5); \n"
"} \n";
void installHighlighter(App& app)
{
osg::StateSet* stateSet = app.mapNode->getOrCreateStateSet();
int attrLocation = Registry::objectIndex()->getObjectIDAttribLocation();
// This shader program will highlight the selected object.
VirtualProgram* vp = VirtualProgram::getOrCreate(stateSet);
vp->setFunction( "checkForHighlight", highlightVert, ShaderComp::LOCATION_VERTEX_CLIP );
vp->setFunction( "highlightFragment", highlightFrag, ShaderComp::LOCATION_FRAGMENT_COLORING );
// Since we're accessing object IDs, we need to load the indexing shader as well:
Registry::objectIndex()->loadShaders( vp );
// A uniform that will tell the shader which object to highlight:
app.highlightUniform = new osg::Uniform("objectid_to_highlight", 0u);
stateSet->addUniform(app.highlightUniform );
}
class ResistryNodeVisitor : public osg::NodeVisitor
{
public:
ResistryNodeVisitor()
: osg::NodeVisitor(TRAVERSE_ALL_CHILDREN)
{
}
~ResistryNodeVisitor()
{
}
void apply(osg::Geometry& node)
{
osgEarth::Registry::objectIndex()->tagNode(&node, &node);
//_geometries.push_back(&node);
traverse(node);
}
public:
/*const std::vector<osg::ref_ptr<osg::PagedLOD> >& pagedlods()
{
return _pagedlods;
}
const std::vector<osg::ref_ptr<osg::Geometry> >& geometries()
{
return _geometries;
}
void clear()
{
_geometries.clear();
_pagedlods.clear();
}*/
private:
/*std::vector<osg::ref_ptr<osg::Geometry> > _geometries;
std::vector<osg::ref_ptr<osg::PagedLOD> > _pagedlods;*/
};
//------------------------------------------------------------------------
// Configures a window that lets you see what the RTT camera sees.
//void
//setupRTTView(osgViewer::View* view, osg::Texture* rttTex)
//{
// view->setCameraManipulator(0L);
// view->getCamera()->setName( "osgearth_pick RTT view" );
// view->getCamera()->setViewport(0,0,256,256);
// view->getCamera()->setClearColor(osg::Vec4(1,1,1,1));
// view->getCamera()->setProjectionMatrixAsOrtho2D(-.5,.5,-.5,.5);
// view->getCamera()->setViewMatrixAsLookAt(osg::Vec3d(0,-1,0), osg::Vec3d(0,0,0), osg::Vec3d(0,0,1));
// view->getCamera()->setProjectionResizePolicy(osg::Camera::FIXED);
//
// osg::Vec3Array* v = new osg::Vec3Array(6);
// (*v)[0].set(-.5,0,-.5); (*v)[1].set(.5,0,-.5); (*v)[2].set(.5,0,.5); (*v)[3].set((*v)[2]); (*v)[4].set(-.5,0,.5);(*v)[5].set((*v)[0]);
//
// osg::Vec2Array* t = new osg::Vec2Array(6);
// (*t)[0].set(0,0); (*t)[1].set(1,0); (*t)[2].set(1,1); (*t)[3].set((*t)[2]); (*t)[4].set(0,1); (*t)[5].set((*t)[0]);
//
// osg::Geometry* g = new osg::Geometry();
// g->setUseVertexBufferObjects(true);
// g->setUseDisplayList(false);
// g->setVertexArray( v );
// g->setTexCoordArray( 0, t );
// g->addPrimitiveSet( new osg::DrawArrays(GL_TRIANGLES, 0, 6) );
//
// osg::Geode* geode = new osg::Geode();
// geode->addDrawable( g );
//
// osg::StateSet* stateSet = geode->getOrCreateStateSet();
// stateSet->setDataVariance(osg::Object::DYNAMIC);
//
// stateSet->setTextureAttributeAndModes(0, rttTex, 1);
// rttTex->setUnRefImageDataAfterApply( false );
// rttTex->setResizeNonPowerOfTwoHint(false);
//
// GLUtils::setLighting(stateSet, 0);
// stateSet->setMode(GL_CULL_FACE, 0);
// stateSet->setAttributeAndModes(new osg::BlendFunc(GL_ONE, GL_ZERO), 1);
//
// const char* fs =
// "#version " GLSL_VERSION_STR "\n"
// "void swap(inout vec4 c) { c.rgba = c==vec4(0)? vec4(1) : vec4(vec3((c.r+c.g+c.b+c.a)/4.0),1); }\n";
// osgEarth::Registry::shaderGenerator().run(geode);
// VirtualProgram::getOrCreate(geode->getOrCreateStateSet())->setFunction("swap", fs, ShaderComp::LOCATION_FRAGMENT_COLORING);
//
// view->setSceneData( geode );
//}
void startPicker(App& app)
{
// Note! Must stop and restart threading when removing the picker
// because it changes the OSG View/Slave configuration.
app.viewer.stopThreading();
app.picker = new RTTPicker();
app.mainView->addEventHandler(app.picker);
ResistryNodeVisitor rn;
app.mapNode->accept(rn);
// add the graph that will be picked.
app.picker->addChild(app.mapNode);
// install a callback that controls the picker and listens for hits.
app.picker->setDefaultCallback(new MyPickCallback(app));
// Make a view that lets us see what the picker sees.
/* if (app.rttView == NULL)
{
app.rttView = new osgViewer::View();
app.rttView->getCamera()->setGraphicsContext(app.mainView->getCamera()->getGraphicsContext());
app.rttView->getCamera()->setSmallFeatureCullingPixelSize(-1.0f);
app.viewer.addView(app.rttView);
}
setupRTTView(app.rttView, app.picker->getOrCreateTexture(app.mainView));
app.rttView->getCamera()->setNodeMask(~0);*/
app.viewer.startThreading();
}
void stopPicker(App& app)
{
// Note! Must stop and restart threading when removing the picker
// because it changes the OSG View/Slave configuration.
app.viewer.stopThreading();
//app.viewer.removeView(app.rttView);
//app.rttView->getCamera()->setNodeMask(0);
app.mainView->removeEventHandler(app.picker);
app.picker = 0L;
app.viewer.startThreading();
}
struct TogglePicker : public ui::ControlEventHandler
{
App& _app;
TogglePicker(App& app) : _app(app) { }
void onClick(Control* button)
{
if (_app.picker == 0L)
startPicker(_app);
else
stopPicker(_app);
}
};
//-----------------------------------------------------------------------
int
usage(const char* name)
{
OE_NOTICE
<< "\nUsage: " << name << " file.earth" << std::endl
<< MapNodeHelper().usage() << std::endl;
return 0;
}
int
main(int argc, char** argv)
{
osg::ArgumentParser arguments(&argc,argv);
if ( arguments.read("--help") )
return usage(argv[0]);
App app(arguments);
app.mainView = new osgViewer::View();
app.mainView->setUpViewInWindow(30, 30, 1024, 1024, 0);
app.mainView->getCamera()->setSmallFeatureCullingPixelSize(-1.0f);
app.viewer.addView(app.mainView);
app.mainView->getDatabasePager()->setUnrefImageDataAfterApplyPolicy( false, false );
app.mainView->setCameraManipulator( new EarthManipulator() );
// Made some UI components:
ui::VBox* uiContainer = new ui::VBox();
uiContainer->setAlign( ui::Control::ALIGN_LEFT, ui::Control::ALIGN_TOP );
uiContainer->setAbsorbEvents( true );
uiContainer->setBackColor(0,0,0,0.8);
uiContainer->addControl( new ui::LabelControl("RTT Picker Test", osg::Vec4(1,1,0,1)) );
uiContainer->addControl( new ui::ButtonControl("Toggle picker", new TogglePicker(app)) );
app.fidLabel = new ui::LabelControl("---");
uiContainer->addControl( app.fidLabel );
app.nameLabel = uiContainer->addControl( new ui::LabelControl( "---" ) );
// Load up the earth file.
osg::Node* node = MapNodeHelper().load( arguments, &app.viewer, uiContainer );
if ( node )
{
app.mainView->setSceneData( node );
app.mapNode = MapNode::get(node);
// start with a picker running
startPicker(app);
// Highlight features as we pick'em.
installHighlighter(app);
app.mainView->getCamera()->setName( "Main view" );
return app.viewer.run();
}
else
{
return usage(argv[0]);
}
}
The results of the run are as follows :
summary :
This paper introduces osgEarth Usage of target picking in , By rewriting RTTPicker::CallBack, Get the picked object , Then borrow shader Highlight the picked object . This article only introduces osgEarth Usage of target pickup , Next, we will further analyze its principle , Research RTTPicker Class and osgEarth Registration system .
边栏推荐
- MXone Pro自适应2.0影视模板西瓜视频主题苹果cmsV10模板
- P1896 [scoi2005] non aggression (shape pressure DP)
- Shader foundation 01
- Three characteristics
- 数据的存储
- Zohocrm deluge function application time verification
- Abstract classes and interfaces
- [usaco12mar]cows in a skyscraper g (state compression DP)
- 详解sizeof、strlen、指针和数组等组合题
- unity2019_ Input management
猜你喜欢
Multi traveling salesman problem -- overview of formula and solution process
Clion toolchains are not configured configure disable profile problem solving
[cocos creator] Click the button to switch the interface
Xlua task list youyou
Ue5 opencv plug-in use
Are you still watching the weather forecast on TV?
Ventuz Foundation Series "one step at the door"
Flex flexible box layout
简易入手《SOM神经网络》的本质与原理
Puhua PLM empowers the whole scene product lifecycle management and helps the enterprise digital transformation of the main line of products
随机推荐
Classes and objects
About Wireshark's unsuccessful installation of npcap
Golang 中string和int类型相互转换
What does (+) in Oracle mean
Clion toolchains are not configured configure disable profile problem solving
KunlunBase MeetUP 等您来!
简易入手《SOM神经网络》的本质与原理
matlab神經網絡所有傳遞函數(激活函數)公式詳解
【音视频】ijkplayer错误码
Detailed explanation of all transfer function (activation function) formulas of MATLAB neural network
Simply start with the essence and principle of SOM neural network
[end of 2021] National Meteorological Short Video (Kwai, Tiktok) influence list in December
oracle中的 (+)是什么意思
matlab神经网络所有传递函数(激活函数)公式详解
Unity change default editor
[cocos creator] Click the button to switch the interface
Lua hot update basic grammar
Ventuz Foundation Series "one step at the door"
Kwai 20200412 recruitment
Redis data structure