VehicleCamera解读
坐标系:
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解读的更多相关文章
- SDWebImage源码解读之SDWebImageDownloaderOperation
第七篇 前言 本篇文章主要讲解下载操作的相关知识,SDWebImageDownloaderOperation的主要任务是把一张图片从服务器下载到内存中.下载数据并不难,如何对下载这一系列的任务进行设计 ...
- SDWebImage源码解读 之 NSData+ImageContentType
第一篇 前言 从今天开始,我将开启一段源码解读的旅途了.在这里先暂时不透露具体解读的源码到底是哪些?因为也可能随着解读的进行会更改计划.但能够肯定的是,这一系列之中肯定会有Swift版本的代码. 说说 ...
- SDWebImage源码解读 之 UIImage+GIF
第二篇 前言 本篇是和GIF相关的一个UIImage的分类.主要提供了三个方法: + (UIImage *)sd_animatedGIFNamed:(NSString *)name ----- 根据名 ...
- SDWebImage源码解读 之 SDWebImageCompat
第三篇 前言 本篇主要解读SDWebImage的配置文件.正如compat的定义,该配置文件主要是兼容Apple的其他设备.也许我们真实的开发平台只有一个,但考虑各个平台的兼容性,对于框架有着很重要的 ...
- SDWebImage源码解读_之SDWebImageDecoder
第四篇 前言 首先,我们要弄明白一个问题? 为什么要对UIImage进行解码呢?难道不能直接使用吗? 其实不解码也是可以使用的,假如说我们通过imageNamed:来加载image,系统默认会在主线程 ...
- SDWebImage源码解读之SDWebImageCache(上)
第五篇 前言 本篇主要讲解图片缓存类的知识,虽然只涉及了图片方面的缓存的设计,但思想同样适用于别的方面的设计.在架构上来说,缓存算是存储设计的一部分.我们把各种不同的存储内容按照功能进行切割后,图片缓 ...
- SDWebImage源码解读之SDWebImageCache(下)
第六篇 前言 我们在SDWebImageCache(上)中了解了这个缓存类大概的功能是什么?那么接下来就要看看这些功能是如何实现的? 再次强调,不管是图片的缓存还是其他各种不同形式的缓存,在原理上都极 ...
- AFNetworking 3.0 源码解读 总结(干货)(下)
承接上一篇AFNetworking 3.0 源码解读 总结(干货)(上) 21.网络服务类型NSURLRequestNetworkServiceType 示例代码: typedef NS_ENUM(N ...
- AFNetworking 3.0 源码解读 总结(干货)(上)
养成记笔记的习惯,对于一个软件工程师来说,我觉得很重要.记得在知乎上看到过一个问题,说是人类最大的缺点是什么?我个人觉得记忆算是一个缺点.它就像时间一样,会自己消散. 前言 终于写完了 AFNetwo ...
随机推荐
- 单链表的C++实现(采用模板类)
采用模板类实现的好处是,不用拘泥于特定的数据类型.就像活字印刷术,制定好模板,就可以批量印刷,比手抄要强多少倍! 此处不具体介绍泛型编程,还是着重叙述链表的定义和相关操作. 链表结构定义 定义单链表 ...
- [精品书单] C#/.NET 学习之路——从入门到放弃
C#/.NET 学习之路--从入门到放弃 此系列只包含 C#/CLR 学习,不包含应用框架(ASP.NET , WPF , WCF 等)及架构设计学习书籍和资料. C# 入门 <C# 本质论&g ...
- 航旅事业群面试(li)
一.JVM 1.如何观察垃圾回收? 2.JAVA应用的JVM参数调优? 3.举例说明你所知道的JVM profile方法? 4.GC tunning实战.假如你是一个大型网站的总架构师,有次web应用 ...
- 利用Spring AOP机制拦截方法一例
直接上代码: @Aspect // for aop @Component // for auto scan @Order(0) // execute before @Transactional pub ...
- observejs改善组件编程体验
传送门 observejs:https://github.com/kmdjs/observejs 本文演示:http://kmdjs.github.io/observejs/list/ 本文代码:ht ...
- iOS学习15之OC集合
1.数组类 1> 回顾C语言数组 数组是一个有序的集合, 来存储相同数据类型的元素. 通过下标访问数组中的元素,下标从 0 开始. 2> 数组 数组是一个有序的集合,OC中的数组只能存储对 ...
- Play Framework 完整实现一个APP(十四)
添加测试 ApplicationTest.java @Test public void testAdminSecurity() { Response response = GET("/adm ...
- Oracle Connect by与递归with
层次查询 select * from emp; select empno, ename, job, mgr, sal, deptno,level lv, sys_connect_by_path(ena ...
- Java实现上传下载
一.上传 二.下载 import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.Fi ...
- Thread Object wait() notify()基本
package com.thread.test.thread; import java.util.ArrayDeque; import java.util.Queue; import java.uti ...