坐标系:

 z-axis
^
|
| y-axis
| /
| /
|/
+----------------> x-axis

围绕Z轴旋转叫做偏航角,Yaw;围绕X轴旋转叫做 俯仰角,Pitch;围绕Y轴旋转,叫做滚转角,Roll 

///////////////////////////////////////////////////////////////////////////////////////////////////////////////

相机的标记:
//使用三个标记,记录相机行进方向;相机无非就是向前,向后,旋转,这三个状态
int m_flags;
int m_forwardFlags;
int m_backwardsFlags;

初始化时:

    m_flags = eVCam_goingForwards | eVCam_canRotate; // 向前 + 可旋转
m_forwardFlags = eVCam_rotationSpring | eVCam_rotationClamp; //带悬架的旋转 + 限制旋转角度
m_backwardsFlags = m_forwardFlags;//和上面那个值一样,所以感觉没什么用处

接受用户输入的旋转:

void CVehicleViewSteer::OnAction(const TVehicleActionId actionId, int activationMode, float value)
{//看看上面的图就了然了
if (m_flags & eVCam_canRotate)
{
if (actionId == eVAI_RotateYaw)
{
m_rotatingAction.z += value;
}
else if (actionId == eVAI_RotatePitch)
{
m_rotatingAction.x += value;
}
}
}

//////////////////////////////////////////////////////////////////////////////////////////////////

    IEntity * pEntity = m_pVehicle->GetEntity();
assert(pEntity); CVehicleMovementBase * pVehicleMovement = static_cast<CVehicleMovementBase*>(m_pVehicle->GetMovement());
const pe_status_dynamics& dynStatus = pVehicleMovement->GetPhysicsDyn(); //这个貌似是取出了物理系统 SMovementState movementState;
pVehicleMovement->GetMovementState(movementState);
const float pedal = pVehicleMovement->GetEnginePedal();//获取坦克引擎力
const float maxSpeed = movementState.maxSpeed;//获取当前坦克的最大速度
const Matrix34& pose = m_pAimPart ? m_pAimPart->GetWorldTM() : pEntity->GetWorldTM();//取出坦克的世界坐标到局部坐标的矩阵
const Vec3 entityPos = pose.GetColumn3();
const Vec3 xAxis = pose.GetColumn0();
const Vec3 yAxis = pose.GetColumn1();
const Vec3 zAxis = pose.GetColumn2();
const float forwardSpeed = dynStatus.v.dot(yAxis);//当前坦克的速度,在Y轴上的投影,就是Y轴方向上的速度了
const float speedNorm = clamp(forwardSpeed / maxSpeed, 0.0f, 1.0f);//计算出这个Y轴的速度与最大速度比例,其实就是个百分比
const Vec3 maxRotation = m_maxRotation + speedNorm * (m_maxRotation2 - m_maxRotation);//这个不知道 CalcLookAt(pose);//根据世界坐标矩阵,计算 m_lookAt,看起来是将look at转到坦克本地坐标系下
if (m_lookAt.IsValid())
{
if (!m_lastOffset.IsValid())
{
       //如果之前没有设置过last offset
m_position = pose * m_localSpaceCameraOffset; //这个应该是想把相机设置到坦克局部坐标系下,同时偏移了一个offset
m_lastOffset = m_position - m_lookAt;// 基本上相当于相机和坦克之间的向量
m_lastOffsetBeforeElev = m_lastOffset;
} Vec3 offset = m_lastOffsetBeforeElev; if (pedal<0.1f && forwardSpeed<1.0f)
{//Y轴速度小于 1,并且当前引擎马力小于 0.1,说明相机要向后移动
// Going Backwards
m_flags &= ~(eVCam_goingForwards | m_forwardFlags);
m_flags |= m_backwardsFlags;
} if (offset.dot(yAxis) < 0.8f && forwardSpeed>.f)
{//Y轴速度大于1,并且上次的偏移在Y轴上的投影大于等于0.8,说明相机要向前移动
// Going Forwards
m_flags &= ~m_backwardsFlags;
m_flags |= eVCam_goingForwards | m_forwardFlags;
}

     
float sensitivity = (.f-speedNorm) * m_stickSensitivity.z + speedNorm * m_stickSensitivity2.z;//影响值。speedNorm是个比例,意义是,在stickSensitivity1,2之间做插值
float rotate = -m_rotatingAction.z * sensitivity;//输入的Z要乘以个0.5,即sensitivity的值
rotate = rotate * dt;//再乘以时间? if (zAxis.z > 0.1f)
{//如果坦克的高度超过 0.1
// Safe to update curYaw
Vec3 projectedX = xAxis; projectedX.z = .f;
Vec3 projectedY = yAxis; projectedY.z = .f;
const float newYaw = atan2_tpl(offset.dot(projectedX), -(offset.dot(projectedY)));
const float maxChange = DEG2RAD(.f)*dt;
const float delta = clamp(newYaw - m_curYaw, -maxChange, +maxChange);
m_curYaw += delta;
} // Rotation Action
{
if (m_flags & eVCam_rotationClamp)
{
float newYaw = clamp(m_curYaw + rotate, -maxRotation.z, +maxRotation.z);
rotate = newYaw - m_curYaw;
rotate = clamp(newYaw - m_curYaw, -fabsf(rotate), +fabsf(rotate));
m_rotation.z += rotate;
}
else
{
m_rotation.z=.f;
} if (speedNorm > 0.1f)
{
float reduce = dt * .f;
m_rotation.z = m_rotation.z - reduce*m_rotation.z/(fabsf(m_rotation.z) + reduce);
}
} // Ang Spring
{
float angSpeedCorrection = dt*dt*m_angSpeedCorrection/(dt*m_angSpeedCorrection+.f)*dynStatus.w.z;
if ((m_flags & eVCam_rotationSpring)==)
{
m_angReturnSpeed = .f;
angSpeedCorrection = .f;
} float difference = m_rotation.z - m_curYaw;
float relax = difference * (m_angReturnSpeed*dt) / ((m_angReturnSpeed*dt) + .f); const float delta = +relax + angSpeedCorrection + rotate;
m_curYaw += delta; Matrix33 rot = Matrix33::CreateRotationZ(delta);
offset = rot * offset; // Lerp the spring speed
float angSpeedTarget = m_angReturnSpeed1 + speedNorm * (m_angReturnSpeed2 - m_angReturnSpeed1);
m_angReturnSpeed += (angSpeedTarget - m_angReturnSpeed) * (dt/(dt+0.3f));
m_angSpeedCorrection += (m_angSpeedCorrection0 - m_angSpeedCorrection) * (dt/(dt+0.3f));
} if (!offset.IsValid()) offset = m_lastOffset; // Velocity influence
Vec3 displacement = -((.f-speedNorm) * dt) * dynStatus.v;//车辆产生位移,这里算的是位移和2倍位移之间的插值,例如,-5和-10之间的插值 float dot = offset.dot(displacement); //Offset 是从相机的偏移位置 到 坦克位置的向量,这个向量和坦克的移动做点积,根据两个向量的方向 ,判断是向前还是向后,再做修正。
if (dot < .f)
{
displacement = displacement + offset * -0.1f * (offset.dot(displacement) / offset.GetLengthSquared());
}
offset = offset + displacement;//这个部分计算的应该是跟随,车辆的移动,需要对偏移值做修正 const float radius0 = fabsf(m_localSpaceCameraOffset.y);
const float minRadius = radius0 * m_radiusMin;
const float maxRadius = radius0 * m_radiusMax;
float radiusXY = sqrtf(sqr(offset.x) + sqr(offset.y)); Vec3 offsetXY = offset; offsetXY.z = .f;
Vec3 accelerationV = (dynStatus.v - m_lastVehVel);//速度变化,加速度
float acceleration = offsetXY.dot(accelerationV) / radiusXY; // m_lastVehVel = dynStatus.v;
m_radiusVel -= acceleration;
m_radius += m_radiusVel * dt - dt*m_radiusVelInfluence * offsetXY.dot(dynStatus.v)/radiusXY;
m_radiusVel *= expf(-dt*m_radiusDampRate);
m_radius += (radius0-m_radius)*(dt*m_radiusRelaxRate)/(dt*m_radiusRelaxRate+.f);
m_radius = clamp(m_radius, minRadius, maxRadius);
offset = offset * (m_radius/radiusXY); // Vertical motion
float targetOffsetHeight = m_localSpaceCameraOffset.z * (m_radius/radius0);//
float oldOffsetHeight = offset.z;
offset.z += (targetOffsetHeight - offset.z)*(dt/(dt+0.3f));
Limit(offset.z, targetOffsetHeight - .f, targetOffsetHeight + .f);
float verticalChange = offset.z - oldOffsetHeight; m_lastOffsetBeforeElev = offset; // Add up and down camera tilt
{
offset.z -= verticalChange;
m_rotation.x += dt * m_stickSensitivity.x * m_rotatingAction.x;
m_rotation.x = clamp(m_rotation.x, -maxRotation.x, +maxRotation.x); float elevAngleVehicle = m_inheritedElev * yAxis.z; // yAxis.z == approx elevation angle float elevationAngle = m_rotation.x - elevAngleVehicle; float sinElev, cosElev;
cry_sincosf(elevationAngle, &sinElev, &cosElev);
float horizLen = sqrtf(offset.GetLengthSquared2D());
float horizLenNew = horizLen * cosElev - sinElev * offset.z;
if (horizLen>1e-4f)
{
horizLenNew /= horizLen;
offset.x *= horizLenNew;
offset.y *= horizLenNew;
offset.z = offset.z * cosElev + sinElev * horizLen;
}
offset.z += verticalChange;
} if (!offset.IsValid()) offset = m_lastOffset; m_position = m_lookAt + offset; // intersection check...
{
IPhysicalEntity* pSkipEntities[];
int nSkip = ;
if(m_pVehicle)
{
nSkip = m_pVehicle->GetSkipEntities(pSkipEntities, );
} primitives::sphere sphere;
sphere.center = m_lookAt;
sphere.r = g_CameraRadius;
Vec3 dir = m_position-m_lookAt; geom_contact *pContact = ;
float hitDist = gEnv->pPhysicalWorld->PrimitiveWorldIntersection(sphere.type, &sphere, dir, ent_static|ent_terrain|ent_rigid|ent_sleeping_rigid,
&pContact, , (geom_colltype_player<<rwi_colltype_bit) | rwi_stop_at_pierceable, , , , pSkipEntities, nSkip);
if(hitDist > 0.0f)
{
// Interpolate the offset
Vec3 newPos = m_lookAt + hitDist * dir.GetNormalizedSafe();
offset = newPos - m_lookAt;
}
} Interpolate(m_lastOffset, offset, .f, dt); m_position = m_lookAt + m_lastOffset;
}
else
{
CRY_ASSERT_MESSAGE(, "camera will fail because lookat position is invalid");
} //float sensitivity = (m_pSensitivity) ? m_pSensitivity->GetFVal() : 1.0f;
m_rotatingAction.zero();

VehicleCamera解读的更多相关文章

  1. SDWebImage源码解读之SDWebImageDownloaderOperation

    第七篇 前言 本篇文章主要讲解下载操作的相关知识,SDWebImageDownloaderOperation的主要任务是把一张图片从服务器下载到内存中.下载数据并不难,如何对下载这一系列的任务进行设计 ...

  2. SDWebImage源码解读 之 NSData+ImageContentType

    第一篇 前言 从今天开始,我将开启一段源码解读的旅途了.在这里先暂时不透露具体解读的源码到底是哪些?因为也可能随着解读的进行会更改计划.但能够肯定的是,这一系列之中肯定会有Swift版本的代码. 说说 ...

  3. SDWebImage源码解读 之 UIImage+GIF

    第二篇 前言 本篇是和GIF相关的一个UIImage的分类.主要提供了三个方法: + (UIImage *)sd_animatedGIFNamed:(NSString *)name ----- 根据名 ...

  4. SDWebImage源码解读 之 SDWebImageCompat

    第三篇 前言 本篇主要解读SDWebImage的配置文件.正如compat的定义,该配置文件主要是兼容Apple的其他设备.也许我们真实的开发平台只有一个,但考虑各个平台的兼容性,对于框架有着很重要的 ...

  5. SDWebImage源码解读_之SDWebImageDecoder

    第四篇 前言 首先,我们要弄明白一个问题? 为什么要对UIImage进行解码呢?难道不能直接使用吗? 其实不解码也是可以使用的,假如说我们通过imageNamed:来加载image,系统默认会在主线程 ...

  6. SDWebImage源码解读之SDWebImageCache(上)

    第五篇 前言 本篇主要讲解图片缓存类的知识,虽然只涉及了图片方面的缓存的设计,但思想同样适用于别的方面的设计.在架构上来说,缓存算是存储设计的一部分.我们把各种不同的存储内容按照功能进行切割后,图片缓 ...

  7. SDWebImage源码解读之SDWebImageCache(下)

    第六篇 前言 我们在SDWebImageCache(上)中了解了这个缓存类大概的功能是什么?那么接下来就要看看这些功能是如何实现的? 再次强调,不管是图片的缓存还是其他各种不同形式的缓存,在原理上都极 ...

  8. AFNetworking 3.0 源码解读 总结(干货)(下)

    承接上一篇AFNetworking 3.0 源码解读 总结(干货)(上) 21.网络服务类型NSURLRequestNetworkServiceType 示例代码: typedef NS_ENUM(N ...

  9. AFNetworking 3.0 源码解读 总结(干货)(上)

    养成记笔记的习惯,对于一个软件工程师来说,我觉得很重要.记得在知乎上看到过一个问题,说是人类最大的缺点是什么?我个人觉得记忆算是一个缺点.它就像时间一样,会自己消散. 前言 终于写完了 AFNetwo ...

随机推荐

  1. 【DDD/CQRS/微服务架构案例】在Ubuntu 14.04.4 LTS中运行WeText项目的服务端

    在<WeText项目:一个基于.NET实现的DDD.CQRS与微服务架构的演示案例>文章中,我介绍了自己用Visual Studio 2015(C# 6.0 with .NET Frame ...

  2. ES6笔记(5)-- Generator生成器函数

    系列文章 -- ES6笔记系列 接触过Ajax请求的会遇到过异步调用的问题,为了保证调用顺序的正确性,一般我们会在回调函数中调用,也有用到一些新的解决方案如Promise相关的技术. 在异步编程中,还 ...

  3. SQL Server Management Studio 无法修改表,超时时间已到 在操作完成之前超时时

    在修改表时,保存的时候显示:无法修改表,超时时间已到 在操作完成之前超时时间已过或服务器未响应 这是执行时间设置过短的原因,可以修改一下设置便能把执行时间加长,以便有足够的时间执行完修改动作. 在 S ...

  4. JQuery的核心的一些方法[扒来的]

    JQuery的核心的一些方法 each(callback) '就像循环 $("Element").length; ‘元素的个数,是个属性 $("Element" ...

  5. Oracle同义词

    Oracle的同义词(synonyms)从字面上理解就是别名的意思,和试图的功能类似,就是一种映射关系.本文介绍如何创建同义词语句,删除同义词以及查看同义词语句. Oracle的同义词总结:从字面上理 ...

  6. python generator next send

    *******oi********oi********oi 上面  *  符号 代表 一系列的代码, oi 代表 一个 [yield]关键字引出的 [数据交换,称之为 oi ] 在一个有[yield] ...

  7. linux(六)__进程与任务控制

    一.程序.进程.线程 1.程序是一个普通文件,是一系列指令和数据的集合,是一个静态的实体,是程序员写好之后存储于外设之上的代码.它是"死"的,而进程和程序都是"活&quo ...

  8. PowerDesigner 常用设置

    1.使用 JDBC 方式连接 Oracle 逆向生成数据库 PDM 使用 ODBC 方式连接 Oracle 数据库可以借鉴这位兄弟的博客:http://www.cnblogs.com/clivehua ...

  9. Why AlloyFinger is so much smaller than hammerjs?

    AlloyFinger is the mobile web gesture solution at present inside my company, major projects are in u ...

  10. ASP.NET的六大内置对象

    ASP.NET 六大内置对象(System.Web.UI.Page类): 1.Response 2.Request 3.Server 4.Application 5.Session 6.Cooki R ...