From 1a4344609c0e58aa3e6b1a9cf7a6f82984337e6c Mon Sep 17 00:00:00 2001 From: Glenn Waldron Date: Wed, 2 Oct 2024 10:00:51 -0400 Subject: [PATCH] Update the osgearth_3pv utility to work with ortho AND to support automatic tracking --- .../osgearth_3pv/osgearth_3pv.cpp | 191 +++++++++--------- .../osgearth_imgui/osgearth_imgui.cpp | 8 +- 2 files changed, 100 insertions(+), 99 deletions(-) diff --git a/src/applications/osgearth_3pv/osgearth_3pv.cpp b/src/applications/osgearth_3pv/osgearth_3pv.cpp index 10febcc360..034b30289f 100644 --- a/src/applications/osgearth_3pv/osgearth_3pv.cpp +++ b/src/applications/osgearth_3pv/osgearth_3pv.cpp @@ -24,14 +24,13 @@ #include #include #include +#include +#include -#include #include #include #include -#include - #define LC "[viewer] " using namespace osgEarth; @@ -45,36 +44,18 @@ using namespace osgEarth; #include #include #include -#include // for putenv - -#if 0 -struct PlacerCallback : public MouseCoordsTool::Callback -{ - PlaceNode* _place; - osg::View* _eyeView; - PlacerCallback(PlaceNode* place, osgViewer::View* eyeView) : _place(place), _eyeView(eyeView) { } - - // called when valid map coordinates are found under the mouse - void set(const GeoPoint& coords, osg::View* view, MapNode* mapNode) - { - _place->setPosition(coords); - _place->setNodeMask(~0); - osg::Vec3d eyeWorld, c, u; - _eyeView->getCamera()->getViewMatrixAsLookAt(eyeWorld, c, u); - osg::Vec3d placeWorld; - coords.toWorld(placeWorld); - - _place->setText( Stringify() << "Range: " << (int)(eyeWorld-placeWorld).length() << "m" ); - } - - // called when no map coords are found under the mouse - void reset(osg::View* view, MapNode* mapNode) - { - _place->setNodeMask(0); +// this shader will outline each terrain tile +const char* outline_shader = R"( + #pragma vp_function outline_tile, fragment + in vec4 oe_layer_tilec; + void outline_tile(inout vec4 color) { + vec2 uv = abs(oe_layer_tilec.xy * 2.0 - 1.0); + if (uv.x > 0.99 || uv.y > 0.99) { + color = vec4(1.0, 0.0, 0.0, 1.0); + } } -}; -#endif +)"; struct CaptureFrustum : public osg::NodeCallback { @@ -116,6 +97,7 @@ createFrustumGeometry() osg::Group* g1 = new osg::Group(); g1->addChild(mt); g1->getOrCreateStateSet()->setRenderBinDetails(3, "RenderBin"); + g1->getOrCreateStateSet()->setRenderBinDetails(3, "RenderBin"); osg::Group* top = new osg::Group(); top->addChild(g0); @@ -135,34 +117,39 @@ createFrustumGeometry() void updateFrustumGeometry(osg::Node* node, const osg::Matrix& modelview, const osg::Matrix& proj) { - // Get near and far from the Projection matrix. - const double near = proj(3,2) / (proj(2,2)-1.0); - const double far = proj(3,2) / (1.0+proj(2,2)); - - // Get the sides of the near plane. - const double nLeft = near * (proj(2,0)-1.0) / proj(0,0); - const double nRight = near * (1.0+proj(2,0)) / proj(0,0); - const double nTop = near * (1.0+proj(2,1)) / proj(1,1); - const double nBottom = near * (proj(2,1)-1.0) / proj(1,1); - - // Get the sides of the far plane. - const double fLeft = far * (proj(2,0)-1.0) / proj(0,0); - const double fRight = far * (1.0+proj(2,0)) / proj(0,0); - const double fTop = far * (1.0+proj(2,1)) / proj(1,1); - const double fBottom = far * (proj(2,1)-1.0) / proj(1,1); + osg::Vec3 LBN, RBN, RTN, LTN, LBF, RBF, RTF, LTF; - LineDrawable* geom = static_cast(node->getUserData()); + if (ProjectionMatrix::isPerspective(proj)) + { + double L, R, B, T, N, F; + ProjectionMatrix::getPerspective(proj, L, R, B, T, N, F); + + double x = F / N; + LBN.set(L, B, -N); + RBN.set(R, B, -N); + RTN.set(R, T, -N); + LTN.set(L, T, -N); + LBF.set(x * L, x * B, -F); + RBF.set(x * R, x * B, -F); + RTF.set(x * R, x * T, -F); + LTF.set(x * L, x * T, -F); + } + else + { + double L, R, B, T, N, F; + ProjectionMatrix::getOrtho(proj, L, R, B, T, N, F); + + LBN.set(L, B, -N); + RBN.set(R, B, -N); + RTN.set(R, T, -N); + LTN.set(L, T, -N); + LBF.set(L, B, -F); + RBF.set(R, B, -F); + RTF.set(R, T, -F); + LTF.set(L, T, -F); + } - osg::Vec3 - LBN(nLeft, nBottom, -near), - RBN(nRight, nBottom, -near), - RTN(nRight, nTop, -near), - LTN(nLeft, nTop, -near), - LBF(fLeft, fBottom, -far), - RBF(fRight, fBottom, -far), - RTF(fRight, fTop, -far), - LTF(fLeft, fTop, -far), - EYE(0,0,0); + LineDrawable* geom = static_cast(node->getUserData()); int i=0; @@ -179,25 +166,32 @@ updateFrustumGeometry(osg::Node* node, const osg::Matrix& modelview, const osg:: geom->setVertex(i++, LTF); geom->setVertex(i++, LBF); // sides - geom->setVertex(i++, EYE); geom->setVertex(i++, LBF); - geom->setVertex(i++, EYE); geom->setVertex(i++, RBF); - geom->setVertex(i++, EYE); geom->setVertex(i++, LTF); - geom->setVertex(i++, EYE); geom->setVertex(i++, RTF); + if (ProjectionMatrix::isPerspective(proj)) + { + geom->setVertex(i++, osg::Vec3()); geom->setVertex(i++, LBF); + geom->setVertex(i++, osg::Vec3()); geom->setVertex(i++, RBF); + geom->setVertex(i++, osg::Vec3()); geom->setVertex(i++, LTF); + geom->setVertex(i++, osg::Vec3()); geom->setVertex(i++, RTF); + } + else + { + geom->setVertex(i++, LBN); geom->setVertex(i++, LBF); + geom->setVertex(i++, RBN); geom->setVertex(i++, RBF); + geom->setVertex(i++, RTN); geom->setVertex(i++, RTF); + geom->setVertex(i++, LTN); geom->setVertex(i++, LTF); + } + + geom->dirty(); osg::MatrixTransform* xform = static_cast(geom->getParent(0)); xform->setMatrix( osg::Matrixd::inverse(modelview) ); } - -char debugEnv[] = "OSGEARTH_REX_DEBUG=1"; - int main( int argc, char** argv ) { osgEarth::initialize(); - putenv(debugEnv); - osg::ArgumentParser arguments( &argc, argv ); osg::ref_ptr< osg::Group > root = new osg::Group; @@ -216,24 +210,32 @@ main( int argc, char** argv ) // Turn on FSAA, makes the lines look better. osg::DisplaySettings::instance()->setNumMultiSamples( 4 ); + bool track = true; + if (arguments.read("--no-track")) + track = false; + + auto modelManip = new EarthManipulator(); + auto spyManip = new EarthManipulator(); + // Create View 0 -- Just the loaded model. { osgViewer::View* view = new osgViewer::View; - viewer.addView( view ); + viewer.addView(view); - view->setUpViewInWindow( 20, 20, 800, 800 ); - view->setSceneData( scene ); - view->setCameraManipulator( new EarthManipulator() ); + view->setUpViewInWindow(20, 20, 1400, 1400); + view->setSceneData(scene); + view->setCameraManipulator(modelManip); } // Create view 1 -- Contains the loaded moel, as well as a wireframe frustum derived from View 0's Camera. { osgViewer::View* view = new osgViewer::View; - viewer.addView( view ); + viewer.addView(view); - view->setUpViewInWindow( 850, 20, 800, 800 ); - view->setSceneData( root.get() ); - view->setCameraManipulator( new EarthManipulator() ); + view->setUpViewInWindow(1450, 20, 1400, 1400); + view->setSceneData(root.get()); + view->setCameraManipulator(spyManip); + spyManip->home(0); } MapNodeHelper helper; @@ -244,36 +246,22 @@ main( int argc, char** argv ) } scene->addChild( node ); + // A shader to outline the terrain tiles. + ShaderLoader::load(scene, outline_shader); + helper.configureView( viewer.getView(0) ); helper.configureView( viewer.getView(1) ); - MapNode* mapNode = MapNode::get(node.get()); - - osg::ref_ptr icon = osgDB::readRefImageFile("../data/placemark32.png"); - PlaceNode* place = new PlaceNode(); - place->setIconImage(icon.get()); - place->setMapNode(mapNode); - place->getOrCreateStateSet()->setRenderBinDetails(10, "DepthSortedBin"); - place->setDynamic(true); - place->setNodeMask(0); - viewer.getView(0)->getCamera()->addChild( place ); - -#if 0 - MouseCoordsTool* mct = new MouseCoordsTool(mapNode); - mct->addCallback( new PlacerCallback(place, viewer.getView(0)) ); - viewer.getView(1)->addEventHandler( mct ); -#endif - - mapNode->addChild(new HorizonNode()); - osg::Matrix proj; viewer.getView(0)->getCamera()->addCullCallback(new CaptureFrustum(proj)); + // This puts the terrain engine into SPY mode. viewer.getView(1)->getCamera()->setName("Spy"); - viewer.getView(1)->getCamera()->setCullCallback( new ObjectStorage::SetValue("osgEarth.Spy", true)); + auto* mapNode = MapNode::get(node); + while (!viewer.done()) { updateFrustumGeometry( @@ -281,6 +269,21 @@ main( int argc, char** argv ) viewer.getView(0)->getCamera()->getViewMatrix(), proj); + if (track) + { + if (viewer.getFrameStamp()->getFrameNumber() == 0) + { + spyManip->home(0); + } + else + { + Viewpoint model_vp = modelManip->getViewpoint(); + Viewpoint sky_vp = spyManip->getViewpoint(); + sky_vp.focalPoint() = model_vp.focalPoint(); + spyManip->setViewpoint(sky_vp); + } + } + viewer.frame(); } return 0; diff --git a/src/applications/osgearth_imgui/osgearth_imgui.cpp b/src/applications/osgearth_imgui/osgearth_imgui.cpp index 2109ad0c21..656852ae99 100644 --- a/src/applications/osgearth_imgui/osgearth_imgui.cpp +++ b/src/applications/osgearth_imgui/osgearth_imgui.cpp @@ -22,7 +22,6 @@ #include #include #include -#include #include #include @@ -80,17 +79,16 @@ main(int argc, char** argv) osgEarth::initialize(arguments); + // Set up the viewer and input handler: osgViewer::Viewer viewer(arguments); viewer.setThreadingModel(viewer.SingleThreaded); viewer.setCameraManipulator(new EarthManipulator(arguments)); - // This is normally called by Viewer::run but we are running our frame loop manually so we need to call it here. - viewer.setReleaseContextAtEndOfFrameHint(false); - // Call this to enable ImGui rendering. // If you use the MapNodeHelper, call this first. viewer.setRealizeOperation(new ImGuiAppEngine::RealizeOperation); + // Load the earth file. osg::ref_ptr node = MapNodeHelper().load(arguments, &viewer); if (node.valid()) { @@ -138,7 +136,7 @@ main(int argc, char** argv) viewer.getEventHandlers().push_front(ui); viewer.setSceneData(node); - return Metrics::run(viewer); + return viewer.run(); } else {