[osg-users] Unwanted culling in 3.6.4 vs 3.5.1
Anders Backman
andersb at cs.umu.se
Thu Jan 9 06:02:10 PST 2020
[image: image.png]
Actually, I managed to reproduce it, sort of in a sample application.
When running this exact code in 3.6.4 I get this:
A quick blink (of a white box), then nothing and lots of culling warnings:
CullVisitor::apply(Geode&) detected NaN,
depth=nan, center=(0 0 7.125),
matrix={
-nan(ind) -nan(ind) -nan(ind) -nan(ind)
-nan(ind) -nan(ind) -nan(ind) -nan(ind)
-nan(ind) -nan(ind) -nan(ind) -nan(ind)
-0.5 -7.125 -45.6982 1
But with 3.5.1 I get:
[image: image.png]
Which is what I would expect.
Anyone that can reproduce this? No models needed, just compile the code
and run.
Cheers,
Anders
On Thu, Jan 9, 2020 at 2:56 PM Anders Backman <andersb at cs.umu.se> wrote:
> That is so strange..!
>
> > osgversion
> OpenSceneGraph Library 3.6.4
>
> Captured a short video of the issue:
> osgviewer --window 0 0 1024 768 osg_3.6.4_culled.osgt
>
> https://gofile.io/?c=A6LCw6
>
> What on earth could be the difference here? Have tested on several
> computers (only Windows though).
> Windows 10, NVida GeForce card.
>
> Also, how it works in 3.5.1:
>
> ">"osgversion
> OpenSceneGraph Library 3.5.1
>
> osgviewer --window 0 0 1024 768 osg_3.5.4_not_culled.osgt
> https://gofile.io/?c=i2Ssx0
>
> On Thu, Jan 9, 2020 at 2:00 PM Voerman, L. <l.voerman at rug.nl> wrote:
>
>> Hi Anders,
>> I did have a quick look, but I can't see any unwanted culling, nor do I
>> get the warnings you write about.
>> tried versions 3.6.3 3.6.4 and 3.6.5 on windows with
>> OSG_NOTIFY_LEVEL=INFO
>> osgviewer osg_3.6.4_culled.osgt
>>
>> Looking in the file I see a lot of empty osg::Text nodes - I guess that
>> causes an empty bounding sphere in the specific version of osg you have.
>> Laurens.
>>
>> On Thu, Jan 9, 2020 at 1:19 PM Anders Backman <andersb at cs.umu.se> wrote:
>>
>>> Another issue I discovered with 3.6.4 is that we now suddenly get
>>> unwanted culling.
>>> At first it looks like a small feature culling thing (which we disable
>>> at global level with:
>>>
>>> // Don't do small feature culling
>>> osg::CullStack::CullingMode cullingMode =
>>> m_viewer->getCamera()->getCullingMode();
>>> cullingMode &= ~(osg::CullStack::SMALL_FEATURE_CULLING);
>>> m_viewer->getCamera()->setCullingMode(cullingMode);
>>>
>>>
>>> However, this does not look like a small feature thing to me at all.
>>> Actually, it culls even when you get close to the objects.
>>> Attached are two osgt-files.
>>>
>>> One is saved from OSG 3.5.1 (works as intended).
>>>
>>> Second one is saved from OSG 3.6.4 (where we get the unwanted culling).
>>>
>>>
>>> If you use a later version of OSG (3.6.4) the one from 3.6.4 generates
>>> lots of warnings:
>>>
>>> CullVisitor::apply(Geode&) detected NaN,
>>> depth=nan, center=(0 0 7.125),
>>> matrix={
>>> -nan(ind) -nan(ind) -nan(ind) -nan(ind)
>>> -nan(ind) -nan(ind) -nan(ind) -nan(ind)
>>> -nan(ind) -nan(ind) -nan(ind) -nan(ind)
>>> 0.187249 -0.470484 -6.20285 1
>>>
>>> whereas the one from 3.5.1 does not.
>>>
>>> Anyone give me a hand on this? I am really stuck.
>>> I was first totally into small feature culling, trying to dig up old
>>> code where people was trying to disable small feature culling on subgraphs
>>> etc. But that is not the issue here.
>>>
>>> Any suggestion would help. I tried to make the scene as small as
>>> possible.
>>>
>>> I tried to attach the files, but it made the message too big.
>>> Instead I shared the files using gofile: https://gofile.io/?c=M5xPmU
>>> There are two files osg_3.5.1_not_culled.osgt
>>> and osg_3.6.4_culled.osgt
>>>
>>> Thanks,
>>> Anders
>>>
>>>
>>> --
>>> __________________________________________
>>> Anders Backman, HPC2N
>>> 90187 Umeå University, Sweden
>>> anders at cs.umu.se http://www.hpc2n.umu.se
>>> Cell: +46-70-392 64 67
>>> _______________________________________________
>>> osg-users mailing list
>>> osg-users at lists.openscenegraph.org
>>> http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org
>>>
>> _______________________________________________
>> osg-users mailing list
>> osg-users at lists.openscenegraph.org
>> http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org
>>
>
>
> --
> __________________________________________
> Anders Backman, HPC2N
> 90187 Umeå University, Sweden
> anders at cs.umu.se http://www.hpc2n.umu.se
> Cell: +46-70-392 64 67
>
--
__________________________________________
Anders Backman, HPC2N
90187 Umeå University, Sweden
anders at cs.umu.se http://www.hpc2n.umu.se
Cell: +46-70-392 64 67
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.openscenegraph.org/pipermail/osg-users-openscenegraph.org/attachments/20200109/fd611d59/attachment-0001.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: image.png
Type: image/png
Size: 23601 bytes
Desc: not available
URL: <http://lists.openscenegraph.org/pipermail/osg-users-openscenegraph.org/attachments/20200109/fd611d59/attachment-0002.png>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: image.png
Type: image/png
Size: 24890 bytes
Desc: not available
URL: <http://lists.openscenegraph.org/pipermail/osg-users-openscenegraph.org/attachments/20200109/fd611d59/attachment-0003.png>
-------------- next part --------------
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2010 Robert Osfield
*
* This application is open source and may be redistributed and/or modified
* freely and without restriction, both in commercial and non commercial applications,
* as long as this copyright notice is maintained.
*
* This application is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
// Include file to get the include of windows.h right, which is a bit tricky.
#ifdef _WIN32
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
# endif
# ifndef NOMINMAX
# define NOMINMAX
# endif
# include <windows.h>
#endif
#ifdef far // Defined in WinDef.h
# undef far
#endif
#ifdef near // Defined in WinDef.h
# undef near
#endif
#ifdef FAR // Defined in WinDef.h; has to be defined again
# undef FAR
# define FAR
#endif
#ifdef NEAR // Defined in WinDef.h; has to be defined again
# undef NEAR
# define NEAR
#endif
#include <osgDB/ReadFile>
#include <osgUtil/Optimizer>
#include <osg/CoordinateSystemNode>
#include <osg/Switch>
#include <osg/Types>
#include <osgText/Text>
#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>
#include <osgGA/TrackballManipulator>
#include <osgGA/FlightManipulator>
#include <osgGA/DriveManipulator>
#include <osgGA/KeySwitchMatrixManipulator>
#include <osgGA/StateSetManipulator>
#include <osgGA/AnimationPathManipulator>
#include <osgGA/TerrainManipulator>
#include <osgGA/SphericalManipulator>
#include <osgGA/Device>
#include <osg/GL2Extensions>
#include <osg/GLExtensions>
#include <osg/Version>
#include <osg/GraphicsContext>
#include <osg/Notify>
#include <iostream>
#include <WinBase.h>
#include <osg/ComputeBoundsVisitor>
#include <osg/MatrixTransform>
class BoundingBoxCallback : public osg::NodeCallback
{
public:
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
{
osg::BoundingBox bb;
for (unsigned int i = 0; i < _nodesToCompute.size(); ++i)
{
osg::Node* node = _nodesToCompute[i];
if (!node->getNumParents())
continue;
osg::ComputeBoundsVisitor cbbv;
node->accept(cbbv);
osg::BoundingBox localBB = cbbv.getBoundingBox();
osg::Matrix localToWorld = osg::computeLocalToWorld(node->getParent(0)->getParentalNodePaths()[0]);
for (unsigned int y = 0; y < 8; ++y)
bb.expandBy(localBB.corner(y) * localToWorld);
}
osg::MatrixTransform* trans = static_cast<osg::MatrixTransform*>(node);
trans->setMatrix(
osg::Matrix::scale(bb.xMax() - bb.xMin(), bb.yMax() - bb.yMin(), bb.zMax() - bb.zMin()) *
osg::Matrix::translate(bb.center()));
traverse(node, nv);
}
osg::NodePath _nodesToCompute;
};
#include <osg/ShapeDrawable>
#include <osg/AutoTransform>
osg::Geode* createContactShapes()
{
const float sphereRadius = 3.f;
const float cylinderRadius = 0.5f;
const float cylinderLength = 12.f;
const float coneHeight = 3.f;
osg::ref_ptr< osg::Shape > shapes[] = {
new osg::Sphere(osg::Vec3(), sphereRadius),
new osg::Cylinder(osg::Vec3(0.f, 0.f, sphereRadius + 0.5f * cylinderLength), cylinderRadius, cylinderLength),
new osg::Cone(osg::Vec3(0.f, 0.f, sphereRadius + cylinderLength), 1.7f * cylinderRadius, coneHeight)
};
const size_t numShapes = sizeof(shapes) / sizeof(osg::ref_ptr< osg::Shape >);
osg::Geode* geode = new osg::Geode();
for (size_t i = 0; i < numShapes; ++i) {
osg::TessellationHints* th = new osg::TessellationHints();
th->setDetailRatio(0.35f);
osg::ShapeDrawable* sd = new osg::ShapeDrawable(shapes[i], th);
geode->addDrawable(sd);
}
return geode;
}
osg::Node *build_scene()
{
auto parent = new osg::Group();
auto child = new osg::Group();
parent->addChild(child);
float scale = 1.0;
float positions[] = { -0.5, -0.5, 0.5, 0.5 };
for (int i = 0; i < 4; i++)
{
auto mt = new osg::MatrixTransform();
mt->setMatrix(osg::Matrix::translate(positions[i], positions[i], 0));
auto obj = new osg::AutoTransform();
mt->addChild(obj);
obj->setAutoRotateMode(osg::AutoTransform::NO_ROTATION);
obj->setAutoScaleToScreen(true);
obj->setAutoScaleTransitionWidthRatio(0.f);
obj->setMaximumScale(0.015 * (double)scale);
obj->setMinimumScale(0.001 * (double)scale);
obj->setPivotPoint(osg::Vec3(0, 0, 0));
auto shape = createContactShapes();
obj->addChild(shape);
child->addChild(mt);
}
/*
*/
// World bounding box callback & node
osg::ref_ptr<BoundingBoxCallback> bbcb = new BoundingBoxCallback;
bbcb->_nodesToCompute.push_back(child);
osg::ref_ptr<osg::Geode> bbgeode = new osg::Geode;
bbgeode->addDrawable(new osg::ShapeDrawable(new osg::Box));
osg::ref_ptr<osg::MatrixTransform> boundingBoxNode = new osg::MatrixTransform;
boundingBoxNode->addChild(bbgeode);
boundingBoxNode->addUpdateCallback(bbcb.get());
boundingBoxNode->getOrCreateStateSet()->setAttributeAndModes(
new osg::PolygonMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE));
boundingBoxNode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
parent->addChild(boundingBoxNode);
return parent;
}
int main(int argc, char** argv)
{
// use an ArgumentParser object to manage the program arguments.
osg::ArgumentParser arguments(&argc, argv);
arguments.getApplicationUsage()->setApplicationName(arguments.getApplicationName());
arguments.getApplicationUsage()->setDescription(arguments.getApplicationName() + " is the standard OpenSceneGraph example which loads and visualises 3d models.");
arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName() + " [options] filename ...");
arguments.getApplicationUsage()->addCommandLineOption("--image <filename>", "Load an image and render it on a quad");
arguments.getApplicationUsage()->addCommandLineOption("--dem <filename>", "Load an image/DEM and render it on a HeightField");
arguments.getApplicationUsage()->addCommandLineOption("-p <filename>", "Play specified camera path animation file, previously saved with 'z' key.");
arguments.getApplicationUsage()->addCommandLineOption("--speed <factor>", "Speed factor for animation playing (1 == normal speed).");
arguments.getApplicationUsage()->addCommandLineOption("--device <device-name>", "add named device to the viewer");
arguments.getApplicationUsage()->addCommandLineOption("--stats", "print out load and compile timing stats");
osg::ref_ptr<osgViewer::Viewer> m_viewer = new osgViewer::Viewer(arguments);
osg::Vec2i windowSize(1200, 720);
m_viewer->setUpViewInWindow(0, 0, windowSize[0], windowSize[1]);
m_viewer->setThreadingModel(osgViewer::Viewer::SingleThreaded);
m_viewer->realize();
osgViewer::Viewer::Windows windows;
m_viewer->getWindows(windows);
osgViewer::GraphicsWindow* window = windows[0];
window->setWindowRectangle(40, 40, windowSize[0], windowSize[1]);
window->setWindowDecoration(true);
m_viewer->frame(); // Force OSG to create an OpenGL context for us before calling agxGL::init().
m_viewer->setReleaseContextAtEndOfFrameHint(false);
m_viewer->frame();
osg::CullStack::CullingMode cullingMode = m_viewer->getCamera()->getCullingMode();
cullingMode &= ~(osg::CullStack::SMALL_FEATURE_CULLING);
m_viewer->getCamera()->setCullingMode(cullingMode);
m_viewer->getCamera()->setSmallFeatureCullingPixelSize(0);
{
osgViewer::Viewer::Windows windows;
m_viewer->getWindows(windows);
if (windows.empty()) {
std::cerr << "Failed to create window when updating vsync" << std::endl;
return 1;
}
osgViewer::GraphicsWindow* window = windows[0];
#if defined(OSG_VERSION_GREATER_OR_EQUAL) && OSG_VERSION_GREATER_OR_EQUAL(2,9,11)
std::cerr << "VSYNK STATUS: " << window->getSyncToVBlank() << std::endl;
window->setSyncToVBlank(false);
#endif
}
unsigned int helpType = 0;
if ((helpType = arguments.readHelpType()))
{
arguments.getApplicationUsage()->write(std::cout, helpType);
return 1;
}
// report any errors if they have occurred when parsing the program arguments.
if (arguments.errors())
{
arguments.writeErrorMessages(std::cout);
return 1;
}
if (arguments.argc() <= 1)
{
arguments.getApplicationUsage()->write(std::cout, osg::ApplicationUsage::COMMAND_LINE_OPTION);
return 1;
}
bool printStats = arguments.read("--stats");
std::string device;
while (arguments.read("--device", device))
{
osg::ref_ptr<osgGA::Device> dev = osgDB::readRefFile<osgGA::Device>(device);
if (dev.valid())
{
m_viewer->addDevice(dev);
}
}
// set up the camera manipulators.
{
osg::ref_ptr<osgGA::KeySwitchMatrixManipulator> keyswitchManipulator = new osgGA::KeySwitchMatrixManipulator;
keyswitchManipulator->addMatrixManipulator('1', "Trackball", new osgGA::TrackballManipulator());
keyswitchManipulator->addMatrixManipulator('2', "Flight", new osgGA::FlightManipulator());
keyswitchManipulator->addMatrixManipulator('3', "Drive", new osgGA::DriveManipulator());
keyswitchManipulator->addMatrixManipulator('4', "Terrain", new osgGA::TerrainManipulator());
keyswitchManipulator->addMatrixManipulator('5', "Orbit", new osgGA::OrbitManipulator());
keyswitchManipulator->addMatrixManipulator('6', "FirstPerson", new osgGA::FirstPersonManipulator());
keyswitchManipulator->addMatrixManipulator('7', "Spherical", new osgGA::SphericalManipulator());
std::string pathfile;
double animationSpeed = 1.0;
while (arguments.read("--speed", animationSpeed)) {}
char keyForAnimationPath = '8';
while (arguments.read("-p", pathfile))
{
osgGA::AnimationPathManipulator* apm = new osgGA::AnimationPathManipulator(pathfile);
if (apm && !apm->getAnimationPath()->empty())
{
apm->setTimeScale(animationSpeed);
unsigned int num = keyswitchManipulator->getNumMatrixManipulators();
keyswitchManipulator->addMatrixManipulator(keyForAnimationPath, "Path", apm);
keyswitchManipulator->selectMatrixManipulator(num);
++keyForAnimationPath;
}
}
m_viewer->setCameraManipulator(keyswitchManipulator.get());
}
// add the state manipulator
m_viewer->addEventHandler(new osgGA::StateSetManipulator(m_viewer->getCamera()->getOrCreateStateSet()));
// add the thread model handler
m_viewer->addEventHandler(new osgViewer::ThreadingHandler);
// add the window size toggle handler
m_viewer->addEventHandler(new osgViewer::WindowSizeHandler);
// add the stats handler
m_viewer->addEventHandler(new osgViewer::StatsHandler);
// add the help handler
m_viewer->addEventHandler(new osgViewer::HelpHandler(arguments.getApplicationUsage()));
// add the record camera path handler
m_viewer->addEventHandler(new osgViewer::RecordCameraPathHandler);
// add the LOD Scale handler
m_viewer->addEventHandler(new osgViewer::LODScaleHandler);
// add the screen capture handler
m_viewer->addEventHandler(new osgViewer::ScreenCaptureHandler);
osg::ElapsedTime elapsedTime;
// load the data
#if 0
osg::ref_ptr<osg::Node> loadedModel = osgDB::readRefNodeFiles(arguments);
if (!loadedModel)
{
std::cout << arguments.getApplicationName() << ": No data loaded" << std::endl;
return 1;
}
if (printStats)
{
double loadTime = elapsedTime.elapsedTime_m();
std::cout << "Load time " << loadTime << "ms" << std::endl;
m_viewer->getStats()->collectStats("compile", true);
}
#else
osg::ref_ptr<osg::Node> loadedModel = build_scene();
#endif
// any option left unread are converted into errors to write out later.
arguments.reportRemainingOptionsAsUnrecognized();
// report any errors if they have occurred when parsing the program arguments.
if (arguments.errors())
{
arguments.writeErrorMessages(std::cout);
return 1;
}
// optimize the scene graph, remove redundant nodes and state etc.
osgUtil::Optimizer optimizer;
optimizer.optimize(loadedModel);
m_viewer->setSceneData(loadedModel);
m_viewer->realize();
return m_viewer->run();
}
More information about the osg-users
mailing list