bool
EarthManipulator::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
{
bool handled = false; // first order of business: make sure the CSN is established.
if ( !established() )
return false; // make sure the camera projection is up to date:
osg::View* view = aa.asView();
updateProjection( view->getCamera() ); double time_s_now = osg::Timer::instance()->time_s(); if ( ea.getEventType() == osgGA::GUIEventAdapter::FRAME )
{
_time_s_last_frame = _time_s_now;
_time_s_now = time_s_now;
_delta_t = _time_s_now - _time_s_last_frame; if ( _node.valid() )
{
if ( _pendingViewpoint.isSet() )
{
setViewpoint( _pendingViewpoint.get(), _pendingViewpointDuration.as(Units::SECONDS) );
_pendingViewpoint.unset();
aa.requestRedraw();
} else if ( isSettingViewpoint() && !isTethering() )
{
if ( _frameCount < )
_setVPStartTime->set(_time_s_now, Units::SECONDS); setViewpointFrame( time_s_now );
} if (_thrown)
{
double decayFactor = 1.0 - _settings->getThrowDecayRate(); _throw_dx = osg::absolute(_throw_dx) > osg::absolute(_dx * 0.01) ? _throw_dx * decayFactor : 0.0;
_throw_dy = osg::absolute(_throw_dy) > osg::absolute(_dy * 0.01) ? _throw_dy * decayFactor : 0.0; if (_throw_dx == 0.0 && _throw_dy == 0.0)
_thrown = false;
else
handleMovementAction(_last_action._type, _throw_dx, _throw_dy, aa.asView());
} aa.requestContinuousUpdate( isSettingViewpoint() || _thrown ); if ( _continuous )
{
handleContinuousAction( _last_action, aa.asView() );
aa.requestRedraw();
}
else
{
_continuous_dx = 0.0;
_continuous_dy = 0.0;
} if ( _task.valid() && _task->_type != TASK_NONE )
{
bool stillRunning = serviceTask();
if ( stillRunning )
{
aa.requestContinuousUpdate( true );
}
else
{
// turn off the continuous, but we still need one last redraw
// to process the final state.
aa.requestContinuousUpdate( false );
aa.requestRedraw();
}
}
} _frameCount++; return false;
} // the camera manipulator runs last after any other event handlers. So bail out
// if the incoming event has already been handled by another handler.
if ( ea.getHandled() )
{
return false;
} // form the current Action based on the event type:
Action action = ACTION_NULL; // if tethering is active, check to see whether the incoming event
// will break the tether.
if ( isTethering() )
{
const ActionTypeVector& atv = _settings->getBreakTetherActions();
if ( atv.size() > )
{
const Action& action = _settings->getAction( ea.getEventType(), ea.getButtonMask(), ea.getModKeyMask() );
if ( std::find(atv.begin(), atv.end(), action._type) != atv.end() )
{
clearViewpoint();
}
}
} if ( ea.isMultiTouchEvent() )
{
// not a mouse event; clear the mouse queue.
resetMouse( aa, false ); // queue up a touch event set and figure out the current state:
addTouchEvents(ea);
TouchEvents te;
if ( parseTouchEvents(te) )
{
for( TouchEvents::iterator i = te.begin(); i != te.end(); ++i )
{
action = _settings->getAction(i->_eventType, i->_mbmask, ); if (action._type != ACTION_NULL)
{
_last_event = i->_eventType; // here we adjust for action scale, global sensitivy
double dx = i->_dx, dy = i->_dy;
dx *= _settings->getMouseSensitivity();
dy *= _settings->getMouseSensitivity();
applyOptionsToDeltas( action, dx, dy ); _dx = dx;
_dy = dy; if (action._type == ACTION_GOTO)
handlePointAction(action, ea.getX(), ea.getY(), view);
else
handleMovementAction(action._type, dx, dy, view); aa.requestRedraw();
}
} handled = true;
}
else
{
// The only multitouch event we want passed on if not handled is a release
handled = ea.getEventType() != osgGA::GUIEventAdapter::RELEASE; // if a new push occurs we want to reset the dx/dy values to stop/prevent throwing
if (ea.getEventType() == osgGA::GUIEventAdapter::PUSH)
_dx = _dy = 0.0;
}
} if ( !handled )
{
// not a touch event; clear the touch queue.
//_touchPointQueue.clear(); switch( ea.getEventType() )
{
case osgGA::GUIEventAdapter::PUSH:
resetMouse( aa );
addMouseEvent( ea );
_mouse_down_event = &ea;
aa.requestRedraw();
handled = true;
break; case osgGA::GUIEventAdapter::RELEASE:
if ( _continuous )
{
// bail out of continuous mode if necessary:
_continuous = false;
aa.requestContinuousUpdate( false );
}
else
{
action = _last_action; _throw_dx = fabs(_dx) > 0.01 ? _dx : 0.0;
_throw_dy = fabs(_dy) > 0.01 ? _dy : 0.0; if (_settings->getThrowingEnabled() && ( time_s_now - _time_s_last_event < 0.05 ) && (_throw_dx != 0.0 || _throw_dy != 0.0))
{
_thrown = true;
aa.requestRedraw();
aa.requestContinuousUpdate( true );
}
else if ( isMouseClick( &ea ) )
{
addMouseEvent( ea );
if ( _mouse_down_event )
{
action = _settings->getAction( EVENT_MOUSE_CLICK, _mouse_down_event->getButtonMask(), _mouse_down_event->getModKeyMask() );
if ( handlePointAction( action, ea.getX(), ea.getY(), aa.asView() ))
aa.requestRedraw();
}
resetMouse( aa );
}
else
{
resetMouse( aa );
addMouseEvent( ea );
}
}
handled = true;
break; case osgGA::GUIEventAdapter::DOUBLECLICK:
// bail out of continuous mode if necessary:
_continuous = false;
addMouseEvent( ea );
if (_mouse_down_event)
{
action = _settings->getAction( ea.getEventType(), _mouse_down_event->getButtonMask(), _mouse_down_event->getModKeyMask() );
if ( handlePointAction( action, ea.getX(), ea.getY(), aa.asView() ) )
aa.requestRedraw();
resetMouse( aa );
handled = true;
}
break; case osgGA::GUIEventAdapter::MOVE: // MOVE not currently bindable
//NOP
break; case osgGA::GUIEventAdapter::DRAG:
{
action = _settings->getAction( ea.getEventType(), ea.getButtonMask(), ea.getModKeyMask() );
addMouseEvent( ea );
bool wasContinuous = _continuous;
_continuous = action.getBoolOption(OPTION_CONTINUOUS, false);
if ( handleMouseAction( action, aa.asView() ) )
aa.requestRedraw(); if ( _continuous && !wasContinuous )
_last_continuous_action_time = time_s_now; //_time_s_now; aa.requestContinuousUpdate(_continuous);
_thrown = false;
handled = true;
}
break; case osgGA::GUIEventAdapter::KEYDOWN:
if ( ea.getKey() < osgGA::GUIEventAdapter::KEY_Shift_L )
{
resetMouse( aa );
action = _settings->getAction( ea.getEventType(), ea.getKey(), ea.getModKeyMask() );
if ( handleKeyboardAction( action ) )
aa.requestRedraw();
handled = true;
}
break; case osgGA::GUIEventAdapter::KEYUP:
resetMouse( aa );
_task->_type = TASK_NONE;
handled = true;
break; case osgGA::GUIEventAdapter::SCROLL:
resetMouse( aa );
addMouseEvent( ea );
action = _settings->getAction( ea.getEventType(), ea.getScrollingMotion(), ea.getModKeyMask() );
if ( handleScrollAction( action, action.getDoubleOption(OPTION_DURATION, 0.2) ) )
aa.requestRedraw();
handled = true;
break;
default: break;
}
} // if a new task was started, request continuous updates.
if ( _task.valid() && _task->_type != TASK_NONE )
{
aa.requestContinuousUpdate( true );
} if ( handled && action._type != ACTION_NULL )
{
_last_action = action;
_time_s_last_event = time_s_now;
} return handled;
}

仔细分析:

            else if ( isSettingViewpoint() && !isTethering() )
{
if ( _frameCount < )
_setVPStartTime->set(_time_s_now, Units::SECONDS); setViewpointFrame( time_s_now );
}

这是需要调整相机漫游器位置了

isSettingViewpoint

这个函数主要是判断当前_setVP0和_setVP1是否有值

有值就从当前_setVP0视点经过一条弧线飞到_setVP1视点下

飞行过程调用的函数就是setViewpointFrame()

// returns "t" [0..1], the interpolation coefficient.
double
CVRECameraManipulator::setViewpointFrame(double time_s)
{
if ( !_setVPStartTime.isSet() )
{
_setVPStartTime->set( time_s, Units::SECONDS );
return 0.0;
}
else
{
// Start point is the current manipulator center:
osg::Vec3d startWorld;
osg::ref_ptr<osg::Node> startNode;
if ( _setVP0->getNode(startNode) )
startWorld = computeWorld(startNode);
else
_setVP0->focalPoint()->transform( _srs.get() ).toWorld(startWorld); // End point is the world coordinates of the target viewpoint:
osg::Vec3d endWorld;
osg::ref_ptr<osg::Node> endNode;
if ( _setVP1->getNode(endNode) )
endWorld = computeWorld(endNode);
else
_setVP1->focalPoint()->transform( _srs.get() ).toWorld(endWorld); // Remaining time is the full duration minus the time since initiation:
double elapsed = time_s - _setVPStartTime->as(Units::SECONDS);
double t = std::min(1.0, elapsed / _setVPDuration.as(Units::SECONDS)); double tp = t; if ( _setVPArcHeight > 0.0 )
{
if ( tp <= 0.5 )
{
double t2 = 2.0*tp;
tp = 0.5*t2;
}
else
{
double t2 = 2.0*(tp-0.5);
tp = 0.5+(0.5*t2);
} // the more smoothsteps you do, the more pronounced the fade-in/out effect
tp = smoothStepInterp( tp );
}
else if ( t > 0.0 )
{
tp = smoothStepInterp( tp );
} osg::Vec3d newCenter =
_srs->isGeographic() ? nlerp(startWorld, endWorld, tp) : lerp(startWorld, endWorld, tp); // Calculate the delta-heading, and make sure we are going in the shortest direction:
Angle d_azim = _setVP1->heading().get() - _setVP0->heading().get();
if ( d_azim.as(Units::RADIANS) > osg::PI )
d_azim = d_azim - Angle(2.0*osg::PI, Units::RADIANS);
else if ( d_azim.as(Units::RADIANS) < -osg::PI )
d_azim = d_azim + Angle(2.0*osg::PI, Units::RADIANS);
double newAzim = _setVP0->heading()->as(Units::RADIANS) + tp*d_azim.as(Units::RADIANS); // Calculate the new pitch:
Angle d_pitch = _setVP1->pitch().get() - _setVP0->pitch().get();
double newPitch = _setVP0->pitch()->as(Units::RADIANS) + tp*d_pitch.as(Units::RADIANS); // Calculate the new range:
Distance d_range = _setVP1->range().get() - _setVP0->range().get();
double newRange =
_setVP0->range()->as(Units::METERS) +
d_range.as(Units::METERS)*tp + sin(osg::PI*tp)*_setVPArcHeight; // Calculate the offsets
osg::Vec3d offset0 = _setVP0->positionOffset().getOrUse(osg::Vec3d(,,));
osg::Vec3d offset1 = _setVP1->positionOffset().getOrUse(osg::Vec3d(,,));
osg::Vec3d newOffset = offset0 + (offset1-offset0)*tp; // Activate.
setLookAt( newCenter, newAzim, newPitch, newRange, newOffset ); // interpolate tether rotation:
_tetherRotation.slerp(tp, _tetherRotationVP0, _tetherRotationVP1); // At t=1 the transition is complete.
if ( t >= 1.0 )
{
_setVP0.unset(); // If this was a transition into a tether, keep the endpoint around so we can
// continue tracking it.
if ( !isTethering() )
{
_setVP1.unset();
}
} return tp;
}
}

setViewpointFrame函数返回的就是0到1之间的插值系数。

注意:_setVPArcHeight   是弧顶高(初始和结束两点之间如果,有一个是最高点则,弧顶高为0)

setViewpointFrame函数里做了:
1.计算当前间隔系数(使其趋近于cos)
2.计算旋转角度、偏航、范围、偏移
3.移动相机setLookAt
4.收尾 ===============================================================================================================
好下面开始动刀:
我要改变OE镜头跳转的速度变化,OE默认速度变化方式是按照cos的方式。就是加速,再减速
我不喜欢,因为最后会出现镜头跳变,我要将cos的方式改成抛物线的方式。(*^__^*) 嘻嘻……

从之前的分析看出,我要修改的就是tp(间隔系数)与传入的时间的关系。

传入时间经过以下转换:

        double elapsed = time_s - _setVPStartTime->as(Units::SECONDS);
double t = std::min(1.0, elapsed / _setVPDuration.as(Units::SECONDS));

  elapsed      是间隔时间

  t = tp      是间隔系数

tp本来是线性[0~1]的,

经过tp = smoothStepInterp( tp );变成了cos的

先把它变回线性的试试。就是去掉

第一次尝试:

tp = tp;直接赋值

得到结果:漫游器以某固定速度飞到另一个点

第二次尝试:(非常失败,但是我还是要记录一下)

double GY_CameraFocal_Time_RatioTurningpoint = 0.2;        //[0.0,  1.0]
double GY_CameraFocal_Distance_RatioTurningpoint = 0.8; //[0.0, 1.0] double GY_SpeedUp_SpeedDown(double timeRatio) {
//输入的是时间比例系数,返回的是距离比例系数;将整个过程分为两个阶段:1.加速阶段,2.减速阶段
/*
//设计整条路径条件是:
一个飞机以初速度speed1向前飞行,并以acceleration1加速度加速飞行,飞行了time1秒;共飞行了distance1米;
然后飞机开始降落,以acceleration2减速度,减速滑行,滑行了time2秒,滑行了distance2米并停下。
已知:time1,time2,distance1,distance2
求:1.初始速度speed1 2.第一段加速度acceleration1 3.第二段加速度acceleration2
最终求:在经过x时间后,当前位置position? 已知公式分析:
1. speed1 * time1 + acceleration1 * time1 * time1 / 2.0 = distance1 //第一段飞行过程
2. speed1 + acceleration1 * time1 + acceleration2 * time2 = 0 //整个过程最后速度为0
3. (speed1 + acceleration1 * time1)* time2 + acceleration2 * time2 * time2 / 2.0 = distance2 //第二段飞行过程 化简公式:
1.sp1*t1 + t1*t1*a1/2 = d1
2.t2*sp1/2.0 + t1*t2*a1/2.0 = d2 解:
sp1 = (d1 - d2)/(t1 - t2/2.0)
a1 = (d2*t1 - d1*t2/2.0)/(t1 - t2/2.0)
a2 = (d1 - d2 + d2*t1*t1 - d1*t1*t2)/(t2*t2/2.0 - t1*t2) 第一段加速导致计算过于复杂,导致,有可能出现初始速度为负数的情况;
直接第一段使用匀速运动,第二段减速
则出现公式:
1.sp1 = d1/time1
2.d2 = sp1 *time2 + a2*time2*time2/2
到处
a2 = 2*(d2 - sp1*t2)/(t2*t2)
但是条件末速度为0,则不会被满足 */
double distanceRatio = timeRatio;
double time1 = osg::clampBetween(GY_CameraFocal_Time_RatioTurningpoint, 0.0, 1.0);
double time2 = 1.0 - time1;
double distance1 = osg::clampBetween(GY_CameraFocal_Distance_RatioTurningpoint, 0.0, 1.0);
double distance2 = 1.0 - distance1;
double speedAtBegin = ;
//double acceleration1 = 0;
double acceleration2 = ;
if (time1 != )
{
speedAtBegin = distance1 / time1;
}
if (time2 != )
{
//a2 = 2*(d2 - sp1*t2)/(t2*t2)
acceleration2 = * (distance2 - speedAtBegin*time2) / (time2*time2);
} if (timeRatio < time1)//加速阶段从0加速到(规定时间1内到达距离1)
{
distanceRatio = timeRatio * speedAtBegin;
}
else//减速阶段从某速度(前一阶段的最后速度)
{
double usetime = timeRatio - time1;
//d2 = sp1 *time2 + a2*time2*time2/2
distanceRatio = distance1 + speedAtBegin*usetime + acceleration2*usetime*usetime /2.0;
} return distanceRatio;//距离系数【0到1】
}

可以看出,我第二次失败是因为考虑了两段不同的加速导致的:最后减速使得,我过了终点后又回倒到终点。。。

高中物理可不管你是否有回倒的过程。。。可耻的应试教育

第三次尝试:

我使用了高等数学的:正态分布算法。

对此,我发现我的数学基础不支持我继续做下去,虽然这应该是最正确的算法。。。我只能找替代

第四次尝试

正态分布的构图让我觉得,我第二次尝试的思路出现了偏颇:

我不应该分两段不同的加速,分两段不同的路径考虑。于是有了下面的代码

double GY_testGaosi(double timeRatio)
{
double distanceRatio = timeRatio;
//s/2 = a*t*t*t/4 前一半 s
// s = a*t*t/2; a = 2*s/t*t
double ac = / 0.25;
//
if (timeRatio < 0.5)
{
distanceRatio = ac*timeRatio*timeRatio / 2.0;
}
else
{
double ftp = 1.0 - timeRatio;
distanceRatio = ac*ftp*ftp / 2.0;
distanceRatio = 1.0 - distanceRatio;
}
return distanceRatio;
}

得出的结果确实比模拟的cos更符合我喜欢的漫游方式,或者说更接近GoogleEarth的漫游方式;

下面给出数据对比

第一组,原来的算法

double
smoothStepInterp( double t ) {
return (t*t)*(3.0-2.0*t);
} 0.000000:::0.000000
0.010000:::0.000298
0.020000:::0.001184
0.030000:::0.002646
0.040000:::0.004672
0.050000:::0.007250
0.060000:::0.010368
0.070000:::0.014014
0.080000:::0.018176
0.090000:::0.022842
0.100000:::0.028000
0.110000:::0.033638
0.120000:::0.039744
0.130000:::0.046306
0.140000:::0.053312
0.150000:::0.060750
0.160000:::0.068608
0.170000:::0.076874
0.180000:::0.085536
0.190000:::0.094582
0.200000:::0.104000
0.210000:::0.113778
0.220000:::0.123904
0.230000:::0.134366
0.240000:::0.145152
0.250000:::0.156250
0.260000:::0.167648
0.270000:::0.179334
0.280000:::0.191296
0.290000:::0.203522
0.300000:::0.216000
0.310000:::0.228718
0.320000:::0.241664
0.330000:::0.254826
0.340000:::0.268192
0.350000:::0.281750
0.360000:::0.295488
0.370000:::0.309394
0.380000:::0.323456
0.390000:::0.337662
0.400000:::0.352000
0.410000:::0.366458
0.420000:::0.381024
0.430000:::0.395686
0.440000:::0.410432
0.450000:::0.425250
0.460000:::0.440128
0.470000:::0.455054
0.480000:::0.470016
0.490000:::0.485002
0.500000:::0.500000
0.510000:::0.514998
0.520000:::0.529984
0.530000:::0.544946
0.540000:::0.559872
0.550000:::0.574750
0.560000:::0.589568
0.570000:::0.604314
0.580000:::0.618976
0.590000:::0.633542
0.600000:::0.648000
0.610000:::0.662338
0.620000:::0.676544
0.630000:::0.690606
0.640000:::0.704512
0.650000:::0.718250
0.660000:::0.731808
0.670000:::0.745174
0.680000:::0.758336
0.690000:::0.771282
0.700000:::0.784000
0.710000:::0.796478
0.720000:::0.808704
0.730000:::0.820666
0.740000:::0.832352
0.750000:::0.843750
0.760000:::0.854848
0.770000:::0.865634
0.780000:::0.876096
0.790000:::0.886222
0.800000:::0.896000
0.810000:::0.905418
0.820000:::0.914464
0.830000:::0.923126
0.840000:::0.931392
0.850000:::0.939250
0.860000:::0.946688
0.870000:::0.953694
0.880000:::0.960256
0.890000:::0.966362
0.900000:::0.972000
0.910000:::0.977158
0.920000:::0.981824
0.930000:::0.985986
0.940000:::0.989632
0.950000:::0.992750
0.960000:::0.995328
0.970000:::0.997354
0.980000:::0.998816
0.990000:::0.999702

第二组,使用了自己的GY_testGaos算法

GY_testGaos
0.000000:::0.000000
0.010000:::0.000200
0.020000:::0.000800
0.030000:::0.001800
0.040000:::0.003200
0.050000:::0.005000
0.060000:::0.007200
0.070000:::0.009800
0.080000:::0.012800
0.090000:::0.016200
0.100000:::0.020000
0.110000:::0.024200
0.120000:::0.028800
0.130000:::0.033800
0.140000:::0.039200
0.150000:::0.045000
0.160000:::0.051200
0.170000:::0.057800
0.180000:::0.064800
0.190000:::0.072200
0.200000:::0.080000
0.210000:::0.088200
0.220000:::0.096800
0.230000:::0.105800
0.240000:::0.115200
0.250000:::0.125000
0.260000:::0.135200
0.270000:::0.145800
0.280000:::0.156800
0.290000:::0.168200
0.300000:::0.180000
0.310000:::0.192200
0.320000:::0.204800
0.330000:::0.217800
0.340000:::0.231200
0.350000:::0.245000
0.360000:::0.259200
0.370000:::0.273800
0.380000:::0.288800
0.390000:::0.304200
0.400000:::0.320000
0.410000:::0.336200
0.420000:::0.352800
0.430000:::0.369800
0.440000:::0.387200
0.450000:::0.405000
0.460000:::0.423200
0.470000:::0.441800
0.480000:::0.460800
0.490000:::0.480200
0.500000:::0.500000
0.510000:::0.519800
0.520000:::0.539200
0.530000:::0.558200
0.540000:::0.576800
0.550000:::0.595000
0.560000:::0.612800
0.570000:::0.630200
0.580000:::0.647200
0.590000:::0.663800
0.600000:::0.680000
0.610000:::0.695800
0.620000:::0.711200
0.630000:::0.726200
0.640000:::0.740800
0.650000:::0.755000
0.660000:::0.768800
0.670000:::0.782200
0.680000:::0.795200
0.690000:::0.807800
0.700000:::0.820000
0.710000:::0.831800
0.720000:::0.843200
0.730000:::0.854200
0.740000:::0.864800
0.750000:::0.875000
0.760000:::0.884800
0.770000:::0.894200
0.780000:::0.903200
0.790000:::0.911800
0.800000:::0.920000
0.810000:::0.927800
0.820000:::0.935200
0.830000:::0.942200
0.840000:::0.948800
0.850000:::0.955000
0.860000:::0.960800
0.870000:::0.966200
0.880000:::0.971200
0.890000:::0.975800
0.900000:::0.980000
0.910000:::0.983800
0.920000:::0.987200
0.930000:::0.990200
0.940000:::0.992800
0.950000:::0.995000
0.960000:::0.996800
0.970000:::0.998200
0.980000:::0.999200
0.990000:::0.999800

第五次尝试:邪恶的尝试

因为对匀加速结果的不太满意,我又尝试了匀加加速度(急动度)

网上TM的连基本的算法都没有···

我只想要一个匀急动度与距离的时间公式而已啊~~汗

没办法,只能近似了,自己编了一个急动度与距离的表达式:s = a*t*t*t/8

//blind add by gaoyuan  -_-!!
double GY_testdong(double timeRatio)
{
double distanceRatio = timeRatio;
//s = a*t*t*t/8 前一半 a = 8*s/t*t*t
double ac = * 0.5 / (0.5*0.5*0.5);
//
if (timeRatio < 0.5)
{
distanceRatio = ac*timeRatio*timeRatio*timeRatio / 8.0;
}
else
{
double ftp = 1.0 - timeRatio;
distanceRatio = ac*ftp*ftp*ftp / 8.0;
distanceRatio = 1.0 - distanceRatio;
}
return distanceRatio;
}

结果,给大家展示一下,不一定能用啊,但是绝对刺激!

0.000000:::0.000000
0.010000:::0.000004
0.020000:::0.000032
0.030000:::0.000108
0.040000:::0.000256
0.050000:::0.000500
0.060000:::0.000864
0.070000:::0.001372
0.080000:::0.002048
0.090000:::0.002916
0.100000:::0.004000
0.110000:::0.005324
0.120000:::0.006912
0.130000:::0.008788
0.140000:::0.010976
0.150000:::0.013500
0.160000:::0.016384
0.170000:::0.019652
0.180000:::0.023328
0.190000:::0.027436
0.200000:::0.032000
0.210000:::0.037044
0.220000:::0.042592
0.230000:::0.048668
0.240000:::0.055296
0.250000:::0.062500
0.260000:::0.070304
0.270000:::0.078732
0.280000:::0.087808
0.290000:::0.097556
0.300000:::0.108000
0.310000:::0.119164
0.320000:::0.131072
0.330000:::0.143748
0.340000:::0.157216
0.350000:::0.171500
0.360000:::0.186624
0.370000:::0.202612
0.380000:::0.219488
0.390000:::0.237276
0.400000:::0.256000
0.410000:::0.275684
0.420000:::0.296352
0.430000:::0.318028
0.440000:::0.340736
0.450000:::0.364500
0.460000:::0.389344
0.470000:::0.415292
0.480000:::0.442368
0.490000:::0.470596
0.500000:::0.500000
0.510000:::0.529404
0.520000:::0.557632
0.530000:::0.584708
0.540000:::0.610656
0.550000:::0.635500
0.560000:::0.659264
0.570000:::0.681972
0.580000:::0.703648
0.590000:::0.724316
0.600000:::0.744000
0.610000:::0.762724
0.620000:::0.780512
0.630000:::0.797388
0.640000:::0.813376
0.650000:::0.828500
0.660000:::0.842784
0.670000:::0.856252
0.680000:::0.868928
0.690000:::0.880836
0.700000:::0.892000
0.710000:::0.902444
0.720000:::0.912192
0.730000:::0.921268
0.740000:::0.929696
0.750000:::0.937500
0.760000:::0.944704
0.770000:::0.951332
0.780000:::0.957408
0.790000:::0.962956
0.800000:::0.968000
0.810000:::0.972564
0.820000:::0.976672
0.830000:::0.980348
0.840000:::0.983616
0.850000:::0.986500
0.860000:::0.989024
0.870000:::0.991212
0.880000:::0.993088
0.890000:::0.994676
0.900000:::0.996000
0.910000:::0.997084
0.920000:::0.997952
0.930000:::0.998628
0.940000:::0.999136
0.950000:::0.999500
0.960000:::0.999744
0.970000:::0.999892
0.980000:::0.999968
0.990000:::0.999996

全部对比:

时间基数 原路程基数  新二阶基数  新三阶基数
0.00 0.000000 0.000000 0.000000
0.02 0.001184 0.000800 0.000032
0.04 0.004672 0.003200 0.000256
0.06 0.010368 0.007200 0.000864
0.08 0.018176 0.012800 0.002048
0.10 0.028000 0.02 0.004000
0.12 0.039744 0.028800 0.006912
0.14 0.053312 0.039200 0.010976
0.16 0.068608 0.051200 0.016384
0.18 0.085536 0.064800 0.023328
0.20 0.104000 0.08 0.032000
0.22 0.123904 0.096800 0.042592
0.24 0.145152 0.115200 0.055296
0.26 0.167648 0.135200 0.070304
0.28 0.191296 0.156800 0.087808
0.30 0.216000 0.18 0.108000
0.32 0.241664 0.204800 0.131072
0.34 0.268192 0.231200 0.157216
0.36 0.295488 0.259200 0.186624
0.38 0.323456 0.288800 0.219488
0.40 0.352000 0.32 0.256000
0.42 0.381024 0.352800 0.296352
0.44 0.410432 0.387200 0.340736
0.46 0.440128 0.423200 0.389344
0.48 0.470016 0.460800 0.442368
0.50 0.50 0.50 0.50
0.52 0.529984 0.539200 0.557632
0.54 0.559872 0.576800 0.610656
0.56 0.589568 0.612800 0.659264
0.58 0.618976 0.647200 0.703648
0.60 0.648000 0.68 0.744000
0.62 0.676544 0.711200 0.780512
0.64 0.704512 0.740800 0.813376
0.66 0.731808 0.768800 0.842784
0.68 0.758336 0.795200 0.868928
0.70 0.784000 0.82 0.892000
0.72 0.808704 0.843200 0.912192
0.74 0.832352 0.864800 0.929696
0.76 0.854848 0.884800 0.944704
0.78 0.876096 0.903200 0.957408
0.80 0.896000 0.92 0.968000
0.82 0.914464 0.935200 0.976672
0.84 0.931392 0.948800 0.983616
0.86 0.946688 0.960800 0.989024
0.88 0.960256 0.971200 0.993088
0.90 0.972000 0.98 0.996000
0.92 0.981824 0.987200 0.997952
0.94 0.989632 0.992800 0.999136
0.96 0.995328 0.996800 0.999744
0.98 0.998816 0.999200 0.999968

第六次尝试,因为老大喜欢最后有一个长长的减速过程,所以,下面的算法,我用了一半时间来实现尾部减速

double GY_SharpMotionAddTail(double timeRatio, double pathLength = 100000.0)
{
timeRatio *= 2.0;
double pathRatio = pathLength / 10000.0;
pathRatio = std::max(1.0, pathRatio); double ratio = 0.1 / pathRatio; double distanceRatio = timeRatio;
//s = a*t*t*t/8 前一半 a = 8*s/t*t*t
double ac = 8 * 0.5 / (0.5*0.5*0.5);
//
if (timeRatio < 0.5)
{
distanceRatio = ac*timeRatio*timeRatio*timeRatio / 8.0;
//distanceRatio *= (1.0 - ratio);
}
else if(timeRatio < 1.0)
{
double ftp = 1.0 - timeRatio;
ftp *= 0.8;//0~0.4
ftp += 0.1;//0.1~0.5
distanceRatio = ac*ftp*ftp*ftp / 8.0;//0~x~0.5 x=0.1*0.1*0.1*a/8.0 x=0.004 //0.004~0.5
distanceRatio = 1 - distanceRatio;//0.5~0.996
distanceRatio -= 0.5;//0~0.496
distanceRatio *= (0.5 - ratio) / 0.496;//0~0.5-ratio
distanceRatio = 0.5 + distanceRatio;//0.5~1-ratio }
else if (timeRatio <= 2)
{
timeRatio = 2.0 - timeRatio;
distanceRatio = 1 - ratio*timeRatio*timeRatio;
}
return distanceRatio;
}

  

[原][osg][osgEarth]EarthManipulator关于oe漫游器的handle部分解读以及修改(仿照谷歌,修改oe漫游器中focal(视角切换)功能 续 二)的更多相关文章

  1. [原][osg][osgEarth]关于在OE中使用物理引擎的调研

    关于物理引擎旋转的一些整理 参考文档 http://blog.wolfire.com/2010/03/Comparing-ODE-and-Bullet 介绍ODE和bullet的利弊 http://s ...

  2. [原][osg][OSGEARTH]OE的关闭打开自动计算裁剪面被OE的海洋ocean影响

    在osgEarthUtil 下 Ocean.cpp 的  traverse函数中: // we don't want the ocean participating in the N/F calcul ...

  3. [原][osg][osgearth]我眼中的osgearth

    看了一下,OE生成的可执行文件 除了osg库和第三方库 OE生产最多的dll就是 osgdb_osgearth_XXXX.dll了 这些都是为了通过osgDB机制加载earth的数据用的. 所以,我觉 ...

  4. [原][osg][osgEarth][粒子特效]关于粒子特效库在osgEarth中,位置摆放问题,跟踪节点移动问题

    首先粒子在地球上位置摆放很简单: //传入的经纬度坐标 osg::Vec3d geoPoint; const SpatialReference* latLong = SpatialReference: ...

  5. [原][osg][osgEarth]osg::Matrix 父子节点的变化关系

    //osg::Matrix offsetmatrix 计算出子节点在父节点下的绝对坐标 //osg::Matrix offposition 用来计算当前节点相对父节点的位置 osg::Matrix o ...

  6. [原][osg][osgearth]简单的通过osgDB,读取高程tif,修改高程tif

    ReadResult result; osg::ref_ptr<osgDB::ReaderWriter> reader = osgDB::Registry::instance()-> ...

  7. [原][OSG][osgEarth]osgEarth例子程序简介

    1.osgearth_graticule:生成经纬线. 2.osgearth_annotation:各类标注(点.线.面.模型.文本等). 3.osgearth_city:加载一个城市三维模型,可以浏 ...

  8. [原][osg][osgearth]倾斜摄影2.文件格式分析:OSGB

    倾斜摄影三维模型格式包含:*.osgb,*.dae等 文件格式包含:*.xml, *.desc, *.lfp等 例如:LocaSpace Viewer软件把osgb分块模型文件建立索引生成一个lfp文 ...

  9. [原][osg][osgearth]倾斜摄影1.介绍

    总体介绍: 倾斜摄影就是将拍好的数据,三角网格化再附上贴图. 目前流行处理软件: Street Factory.PIX4DMapper.smart3D 后期开发平台:超图 Skyline smart3 ...

随机推荐

  1. Spring Boot 实现RESTful webservice服务端示例

    1.Spring Boot configurations application.yml spring: profiles: active: dev mvc: favicon: enabled: fa ...

  2. QMenu 设置菜单图标 & 生成菜单树

    效果图 源码 .h 文件 protected slots: void onMenuTriggered(QAction*); .cpp 文件 // 菜单 QMenu *pMenu = new QMenu ...

  3. OpenGL: 实现立体显示

    https://blog.csdn.net/augusdi/article/details/19922295 立体显示原理:设没有立体显示的模型视图矩阵ModelView为Mv,投影矩阵为Mp,则.物 ...

  4. priority todo

    analyze the work about change to right spindle

  5. Fiddler抓取指定域名

    有时候我们抓取app软件的包时,其他很多软件进程的请求会造成干扰 这时我们就需要过滤只抓取我们需要域名的包 切换到Fiddler右侧窗口的Filters选项卡,勾选顶部的Use Filters,找到H ...

  6. python3 获取cookie解决方案

    python3 获取cookie解决方案 方案一: 利用selenium+phantomjs无界面浏览器的形式访问网站,再获取cookie值: from selenium import webdriv ...

  7. 在见证了1000多家公司的兴衰灭亡之后,YC创始合伙人总结了创业公司的6个不死法则(转)

    今天,我想先说一下个人消息.在 YC 工作了 11 年之后,我明年想去休假.我希望把精力放在一些项目上,说实话,我有点累了. YC 是这世界上我最喜欢的事情之一,但它也很费精力. 11 年不间断的耗费 ...

  8. 【题解】Luogu P2157 [SDOI2009]学校食堂

    原题传送门:P2157 [SDOI2009]学校食堂 一看题目就知道是状压dp 设f[i][j][k]表示第1到i-1个人都吃完了饭,第i个人以及后面的7个人是否打饭的状态为j,当前最后打饭的人的编号 ...

  9. 01:adminLTE2基本使用

    1.1 adminLTE介绍 1.adminLTE 介绍 1.基于Bootstrap3高度可定制的响应式管理模板,免去前端架构师大量的js和css的编写 2.adminLTE除了可以使用bootstr ...

  10. iOS App架构相关

    一) 我们可以定义一个好的架构应该具备的特点: 任务均衡分摊给具有清晰角色的实体 可测试性通常都来自与上一条(对于一个合适的架构是非常容易) 易用性和低成本维护 二) 传统的MVC模式.:三个实体间相 ...