当前位置:网站首页>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 .
边栏推荐
- Transplantation of freetype Library
- Chain length value
- P1596 [USACO10OCT]Lake Counting S
- P2704 [NOI2001] 炮兵阵地(状压dp)
- UE4 plug in development
- WPF:解决MaterialDesign:DialogHost 无法关闭问题
- One dimensional array two dimensional array (sort Max insert sort)
- GIS实战应用案例100篇(七十八)-多规合一数据库设计及数据入库
- P2622 关灯问题II(状态压缩 搜索)
- Puhua PLM empowers the whole scene product lifecycle management and helps the enterprise digital transformation of the main line of products
猜你喜欢
Are you still watching the weather forecast on TV?
Image processing 8-cnn image classification
C language - Introduction - essence Edition - take you into programming (I)
图像处理8-CNN图像分类
MAE
Transplantation of freetype Library
Open the influence list of "National Meteorological Short Videos (Kwai, Tiktok) in November" in an interactive way“
jupyter远程服务器配置以及服务器开机自启
C#课程设计之学生教务管理系统
Basic operation and process control
随机推荐
C course design employee information management system
CLion-Toolchains are not configured Configure Disable profile问题解决
C#课程设计之员工信息管理系统
Use filechannel to copy files
P1896 [scoi2005] non aggression (shape pressure DP)
2021-10-19
Scite change background color
L'installateur a été installé avec une erreur inattendue
数据分析练习题
Encoding and decoding of golang URL
KunlunBase MeetUP 等您来!
Easy touch plug-in
Puhua PLM empowers the whole scene product lifecycle management and helps the enterprise digital transformation of the main line of products
Lua hot update basic grammar
P2622 light off problem II (state compression search)
Go resolve ID card
Huawei interview summary during the epidemic
简易入手《SOM神经网络》的本质与原理
Luaframwrok handles resource updates
Detailed explanation of all transfer function (activation function) formulas of MATLAB neural network