From d191a528470b990be094bf243b697694ad159dda Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Sep 2015 18:10:02 +0200 Subject: [PATCH] Create occlusion query nodes for the sun flash --- apps/openmw/mwrender/sky.cpp | 57 ++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 67e842c8d..3d2b35c37 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -11,6 +11,9 @@ #include #include #include +#include +#include +#include #include #include @@ -368,6 +371,18 @@ public: osg::Texture::CLAMP); mGeode->getOrCreateStateSet()->setTextureAttributeAndModes(0, sunTex, osg::StateAttribute::ON); + + // Slightly downscale the query geometry since the sun quad has a transparent texture that doesn't cover the whole area + osg::ref_ptr queryTransform (new osg::PositionAttitudeTransform); + queryTransform->setScale(osg::Vec3f(0.5f, 0.5f, 0.5f)); + // Need to render after the world geometry so we can correctly test for occlusions + queryTransform->getOrCreateStateSet()->setRenderBinDetails(10, "RenderBin"); + queryTransform->getOrCreateStateSet()->setNestRenderBins(false); + + mTransform->addChild(queryTransform); + + mOcclusionQueryVisiblePixels = createOcclusionQueryNode(queryTransform, true); + mOcclusionQueryTotalPixels = createOcclusionQueryNode(queryTransform, false); } ~Sun() @@ -391,6 +406,46 @@ public: } private: + /// @param queryVisible If true, queries the amount of visible pixels. If false, queries the total amount of pixels. + osg::ref_ptr createOcclusionQueryNode(osg::Group* parent, bool queryVisible) + { + osg::ref_ptr oqn = new osg::OcclusionQueryNode; + oqn->setQueriesEnabled(true); + + // Make it fast! A DYNAMIC query geometry means we can't break frame until the flare is rendered (which is rendered after all the other geometry, + // so that would be pretty bad). STATIC should be safe, since our node's local bounds are static, thus computeBounds() which modifies the queryGeometry + // is only called once. + // Note the debug geometry setDebugDisplay(true) is always DYNAMIC and that can't be changed, not a big deal. + oqn->getQueryGeometry()->setDataVariance(osg::Object::STATIC); + + osg::ref_ptr queryGeode = osg::clone(mGeode.get(), osg::CopyOp::DEEP_COPY_ALL); + // Disable writing to the color buffer. We are using this geode for visibility tests only. + osg::ref_ptr colormask (new osg::ColorMask(0, 0, 0, 0)); + queryGeode->getOrCreateStateSet()->setAttributeAndModes(colormask, osg::StateAttribute::ON); + + oqn->addChild(queryGeode); + + if (queryVisible) + { + osg::ref_ptr depth (new osg::Depth); + depth->setFunction(osg::Depth::LESS); + // This is a trick to make fragments written by the query always use the maximum depth value, + // without having to retrieve the current far clipping distance. + // We want the sun glare to be "infinitely" far away. + depth->setZNear(1.0); + depth->setZFar(1.0); + oqn->getQueryStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON); + } + else + { + oqn->getQueryStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); + } + + parent->addChild(oqn); + + return oqn; + } + struct Updater : public SceneUtil::StateSetUpdater { osg::Vec4f mColor; @@ -414,6 +469,8 @@ private: }; osg::ref_ptr mUpdater; + osg::ref_ptr mOcclusionQueryVisiblePixels; + osg::ref_ptr mOcclusionQueryTotalPixels; }; class Moon : public CelestialBody