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

时间:2022-02-03 17:24:44

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:\n"
<< " from " << _setVP0->toString() << "\n"
<< " to " << _setVP1->toString() << "\n"; // 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