[osgearth][原]仿照谷歌,修改oe漫游器中focal(视角切换)功能

oe中的视角加速感觉好奇怪,就仿照谷歌方式去改了。

先看看oe原来的漫游器改变视角的接口:

void
CameraManipulator::setViewpoint(const Viewpoint& vp, double duration_seconds)
{
    // If the manip is not set up, save the viewpoint for later.
    if ( !established() )
    {
        _pendingViewpoint = vp;
        _pendingViewpointDuration.set(duration_seconds, Units::SECONDS);
    }

    else
    {
        // Save any existing tether node so we can properly invoke the callback.
        osg::ref_ptr<osg::Node> oldEndNode;
        if ( isTethering() && _tetherCallback.valid() )
            _setVP1->getNode(oldEndNode);

        // starting viewpoint; all fields will be set:
        _setVP0 = getViewpoint();

        // ending viewpoint
        _setVP1 = vp;

        // Reset the tethering offset quat.
        _tetherRotationVP0 = _tetherRotation;
        _tetherRotationVP1 = osg::Quat();

        // Fill in any missing end-point data with defaults matching the current camera setup.
        // Then all fields are guaranteed to contain usable data during transition.
        double defPitch, defAzim;
        getEulerAngles( _rotation, &defAzim, &defPitch );

        if ( !_setVP1->heading().isSet() )
            _setVP1->heading() = Angle(defAzim, Units::RADIANS);

        if ( !_setVP1->pitch().isSet() )
            _setVP1->pitch() = Angle(defPitch, Units::RADIANS);

        if ( !_setVP1->range().isSet() )
            _setVP1->range() = Distance(_distance, Units::METERS);

        if ( !_setVP1->nodeIsSet() && !_setVP1->focalPoint().isSet() )
        {
            osg::ref_ptr<osg::Node> safeNode;
            if ( _setVP0->getNode( safeNode ) )
                _setVP1->setNode( safeNode.get() );
            else
                _setVP1->focalPoint() = _setVP0->focalPoint().get();
        }

        _setVPDuration.set( std::max(duration_seconds, 0.0), Units::SECONDS );

        OE_DEBUG << LC << "setViewpoint:
"
            << "    from " << _setVP0->toString() << "
"
            << "    to   " << _setVP1->toString() << "
";

        // access the new tether node if it exists:
        osg::ref_ptr<osg::Node> endNode;
        _setVP1->getNode(endNode);

        // Timed transition, we need to calculate some things:
        if ( duration_seconds > 0.0 )
        {
            // Start point is the current manipulator center:
            osg::Vec3d startWorld;
            osg::ref_ptr<osg::Node> startNode;
            startWorld = _setVP0->getNode(startNode) ? computeWorld(startNode.get()) : _center;

            _setVPStartTime.unset();

            // End point is the world coordinates of the target viewpoint:
            osg::Vec3d endWorld;
            if ( endNode.valid() )
                endWorld = computeWorld(endNode.get());
            else
                _setVP1->focalPoint()->transform( _srs.get() ).toWorld(endWorld);

            // calculate an acceleration factor based on the Z differential.
            _setVPArcHeight = 0.0;
            double range0 = _setVP0->range()->as(Units::METERS);
            double range1 = _setVP1->range()->as(Units::METERS);

            double pitch0 = _setVP0->pitch()->as(Units::RADIANS);
            double pitch1 = _setVP1->pitch()->as(Units::RADIANS);

            double h0 = range0 * sin( -pitch0 );
            double h1 = range1 * sin( -pitch1 );
            double dh = (h1 - h0);

            // calculate the total distance the focal point will travel and derive an arc height:
            double de = (endWorld - startWorld).length();

            // maximum height during viewpoint transition
            if ( _settings->getArcViewpointTransitions() )
            {
                _setVPArcHeight = osg::maximum( de - fabs(dh), 0.0 );
            }

            // calculate acceleration coefficients
            if ( _setVPArcHeight > 0.0 )
            {
                // if we're arcing, we need seperate coefficients for the up and down stages
                double h_apex = 2.0*(h0+h1) + _setVPArcHeight;
                double dh2_up = fabs(h_apex - h0)/100000.0;
                _setVPAccel = log10( dh2_up );
                double dh2_down = fabs(h_apex - h1)/100000.0;
                _setVPAccel2 = -log10( dh2_down );
            }
            else
            {
                // on arc => simple unidirectional acceleration:
                double dh2 = (h1 - h0)/100000.0;
                _setVPAccel = fabs(dh2) <= 1.0? 0.0 : dh2 > 0.0? log10( dh2 ) : -log10( -dh2 );
                if ( fabs( _setVPAccel ) < 1.0 ) _setVPAccel = 0.0;
            }

            // Adjust the duration if necessary.
            if ( _settings->getAutoViewpointDurationEnabled() )
            {
                double maxDistance = _srs->getEllipsoid()->getRadiusEquator();
                double ratio = osg::clampBetween( de/maxDistance, 0.0, 1.0 );
                ratio = accelerationInterp( ratio, -4.5 );
                double minDur, maxDur;
                _settings->getAutoViewpointDurationLimits( minDur, maxDur );
                _setVPDuration.set( minDur + ratio*(maxDur-minDur), Units::SECONDS );
            }
        }

        else
        {
            // Immediate transition? Just do it now.
            _setVPStartTime->set( _time_s_now, Units::SECONDS );
            setViewpointFrame( _time_s_now );
        }

        // Fire a tether callback if required.
        if ( _tetherCallback.valid() )
        {
            // starting a tether to a NEW node:
            if ( isTethering() && oldEndNode.get() != endNode.get() )
                (*_tetherCallback)( endNode.get() );

            // breaking a tether:
            else if ( !isTethering() && oldEndNode.valid() )
                (*_tetherCallback)( 0L );
        }
    }

    // reset other global state flags.
    _thrown      = false;
    _task->_type = TASK_NONE;
}

 这里有几个重点参数:

osgEarth::optional<osgEarth::Viewpoint>  _setVP0和_setVP1 :开始视点,结束视点

double                  _setVPAccel, _setVPAccel2; 开始点去最高点加速度,最高点去结束点加速度

修改方案:https://www.cnblogs.com/lyggqm/p/8534619.html

原文地址:https://www.cnblogs.com/lyggqm/p/8404230.html