OGRE+PhysX仿魔兽世界摄像机
来源:互联网 发布:如何在阿里云建网站 编辑:程序博客网 时间:2024/04/30 06:11
OGRE+PhysX仿魔兽世界摄像机(包含碰撞,跟随,防墙体穿透以及摄像头不被遮挡)的实现(10/7更新,封装了下)
刚终于解决了摄像机的问题,写个文交流交流先~
做法其实蛮简单,场景是PhysX(部分用的NxOgre)的TriangleMesh + Ogre新地形,可视部分建筑物可耻的用了天龙八部的资源,然后判断摄像头的位置用PhysX的raycastClosestShape()。人物移动用的PhysX的CC,可视部分用的Ogre源DEMO-Sinbad那个,改了改~
基本思路也就是一个SceneNode在BodyNode头上面一点(我这儿没有用传说中的五点检测法,感觉太费时,不过一个点的效果也蛮好~),然后SceneNode子节点一个不做任何碰撞检测与不挂接摄像机的节点做射线检测方向,由头上面那个SceneNode引射线至其子节点,检测最近的碰撞点,然后把另一个挂接了Camera的SceneNode移到碰撞点并LookAt头上那个SceneNode。同时,为了保证不穿墙且不看到截面,最好是能附带检测Frustum的四个边点。然后确保当无视线阻挡时能自动恢复,需要判断hit.distance > length,反正就是魔兽那效果啦~ 摄像机位置回复时最好能根据时间插值,看上去舒服点。
需要注意的是:
1.节点的获取位置函数问题,对于无parent的节点,getPosition()是获取的当前帧改变后的位置值,而_getDerivedPosition()需要render一次后才更新;对于有parent的节点,getPosition()获取的是该帧修改后的相对值,而_getDerivedPosition()是获取的未更新的世界坐标。记得要获得子节点的当前帧最新位置,要用_update(true,true);
2.小心转向角的问题,把Pitch和Yaw的角度可得锁好了,不然到时会很乱,最好能像魔兽世界那样,摄像机动,人也动,若处于摄像机拖着浏览人物周身状态,按下行走键时马上恢复到背对状态~
3.又优化了几天,发现一些小问题,比如人物在死角的时候摄像头的位置处理,我仿魔兽的将摄像头坐标直接设在了人物身上,然后朝对面看;比如当离开阻挡物后视角的缓慢恢复;比如有些小穿透的地方。。。看代码吧~很多诡异的小问题,不过现在基本上已经差不多了,就差魔兽的在房子里面的视角缓慢恢复了,这个是蛮好加的,就是有些小地方要注意~
好,上图:
基本代码体系大家参考Ogre的那个SinbadDemo和QtOgitor的Demo,基本都出自那儿,当然,要是只取摄像机部分的话可以看SetupCamera(),SetupBody(),UpdateBody(),updateCamera(),updateCameraGoal(),这些就行~ 祝你好运,有好的建议或不明白的欢迎评论指教哈~
上代码:
.h
01
#include "Ogre.h"
02
#include "NxScene.h"
03
#include "NxRay.h"
04
#include "OgreTerrainGroup.h"
05
06
//std::pair<Ogre::SceneNode *,NxActor *> NodeActorPair;
07
08
using
namespace
Ogre;
09
class
MyCameraController
10
{
11
private
:
12
/*
13
NxRevoluteJoint * mJoint;
14
NxSpringDesc * mSpringDesc;
15
Ogre::SceneManager * mSceneMgr;
16
NxRay mRay;
17
NodeActorPair * mCaracter;
18
NodeActorPair * mCamera;*/
19
20
SceneNode * mCameraPivot;
21
SceneNode * mCameraNode;
22
SceneNode * mCameraOriginal;
23
SceneNode * mBodyNode;
24
Camera * mCamera;
25
NxRaycastHit mHitPoint;
26
NxScene * mNxScene;
27
bool
bViewRestore;
28
float
mPivotPitch;
29
Ogre::TerrainGroup * mTerrainGroup;
30
31
public
:
32
//MyCameraController(Ogre::SceneManager * sceneMgr,NxScene * scene,NodeActorPair * caracter,NodeActorPair * camera) : mSceneMgr(sceneMgr), mNxScene(scene), mCamera(caracter)
33
MyCameraController(Camera * camera,SceneNode * body,NxScene * scene,TerrainGroup * tg) : mCamera(camera), mBodyNode(body), mNxScene(scene), mTerrainGroup(tg), bViewRestore(
false
), mPivotPitch(0.0f)
34
{
35
setup();
36
}
37
38
void
setup();
39
void
update(
float
deltaTime);
40
void
updateGoal(
float
pitchAngle,
float
yawAngle,
float
deltaZoom);
41
42
SceneNode * getCameraPivot()
43
{
44
return
mCameraPivot;
45
}
46
};
.cpp
001
#include "MyCameraController.h"
002
003
void
MyCameraController::setup()
004
{
005
SceneManager * sMgr = mCamera->getSceneManager();
006
mCameraPivot = sMgr->getRootSceneNode()->createChildSceneNode();
007
mCameraOriginal = mCameraPivot->createChildSceneNode(Vector3(0,3,-20));
008
mCameraNode = sMgr->getRootSceneNode()->createChildSceneNode();
009
010
mCameraNode->attachObject(mCamera);
011
012
mCameraNode->setFixedYawAxis(
true
);
013
mCameraOriginal->setFixedYawAxis(
true
);
014
mCameraPivot->setFixedYawAxis(
true
);
015
}
016
017
void
MyCameraController::update(
float
deltaTime)
018
{
019
mCameraPivot->setPosition(mBodyNode->getPosition() + Vector3(0,2.2f,0));
020
mCameraOriginal->_update(
true
,
true
);
021
mCameraOriginal->lookAt(mCameraPivot->getPosition(),Node::TS_WORLD);
022
023
Vector3 vo = mCameraOriginal->_getDerivedPosition();
024
Vector3 vb = mCameraPivot->_getDerivedPosition();
025
Ogre::Ray ray;
026
NxVec3 vc(vb.x,vb.y,vb.z);
027
NxVec3 vecDir = NxVec3(vo.x - vb.x,vo.y - vb.y,vo.z - vb.z);
028
float
length = vecDir.normalize();
029
NxRay nxRay(vc,vecDir);
030
NxRaycastHit hit;
031
NxShape * shape = mNxScene->raycastClosestShape(nxRay,NX_ALL_SHAPES,hit);
032
033
if
(shape && hit.distance < length)
034
{
035
Vector3 hitWorld(hit.worldImpact.x,hit.worldImpact.y,hit.worldImpact.z);
036
037
//为了防止穿透
038
float
transZ = -0.8f;
039
//float transY = (-0.8f) * vo.y / (NxMath::sqrt(vo.x * vo.x + vo.z * vo.z)); //这个还是算了,不加上去。。。
040
hitWorld += mCameraOriginal->_getDerivedOrientation() * Vector3(0,0,transZ);
041
Vector3 hitLocal = -mCameraPivot->convertWorldToLocalPosition(hitWorld);
042
mCameraNode->setPosition(hitWorld);
043
mCameraNode->lookAt(mCameraPivot->getPosition(),Node::TS_WORLD);
044
045
//为了防止在角落里时摄像机反向
046
if
(hitLocal.z < 0)
047
{
048
mCameraNode->setPosition(mCameraPivot->getPosition() + Vector3(0,1.1,0));
//这个效果和魔兽世界还有暗黑血统相似,但他们是不是这么写的就不得而知了~ 呵呵
049
Vector3 v = mCameraPivot->getOrientation() * Vector3(0,0,3);
050
mCameraNode->lookAt(mCameraPivot->getPosition() + v,Node::TS_WORLD);
051
}
052
bViewRestore =
true
;
053
}
054
else
055
{
056
if
(bViewRestore)
057
{
058
Vector3 transPos = vo - mCameraNode->getPosition();
059
Vector3 localPos = mCameraPivot->convertWorldToLocalPosition(mCameraNode->getPosition());
060
Vector3 originalPos = mCameraOriginal->getPosition();
061
if
(localPos.z > originalPos.z)
062
{
063
localPos.z -= 25 * deltaTime;
064
}
065
if
(localPos.z <= originalPos.z)
066
{
067
localPos.z = originalPos.z;
068
bViewRestore =
false
;
069
}
070
else
071
originalPos.z = localPos.z;
072
073
mCameraNode->setPosition(mCameraPivot->convertLocalToWorldPosition(originalPos));
074
}
075
else
076
mCameraNode->setPosition(vo);
077
078
mCameraNode->lookAt(mCameraPivot->getPosition(),Node::TS_WORLD);
079
}
080
081
Vector3 cameraNodePos = mCameraNode->getPosition();
082
float
height = mTerrainGroup->getHeightAtWorldPosition(cameraNodePos.x,0,cameraNodePos.z) + 0.5;
083
if
(cameraNodePos.y < height)
084
{
085
cameraNodePos.y = height;
086
mCameraNode->setPosition(cameraNodePos);
087
}
088
}
089
090
void
MyCameraController::updateGoal(
float
pitchAngle,
float
yawAngle,
float
deltaZoom)
091
{
092
mCameraPivot->yaw(Degree(yawAngle),Node::TS_LOCAL);
093
//mBodyNode->yaw(Degree(deltaYaw),Node::TS_LOCAL);
094
095
//if(mPivotPitch + pitchAngle <= 60 && mPivotPitch + pitchAngle >= -40)
096
{
097
mCameraPivot->pitch(Degree(pitchAngle), Node::TS_LOCAL);
098
mPivotPitch += pitchAngle;
099
}
100
101
Real dist = mBodyNode->_getDerivedPosition().distance(mCameraOriginal->_getDerivedPosition());
102
Real distChange = deltaZoom * dist;
103
104
// bound the zoom
105
if
(!bViewRestore && dist + distChange >= 6 && dist + distChange <= 28)
106
{
107
mCameraOriginal->translate(0, 0, distChange, Node::TS_LOCAL);
108
}
109
}
- OGRE+PhysX仿魔兽世界摄像机
- OGRE+PhysX仿魔兽世界摄像机(包含碰撞,跟随,防墙体穿透以及摄像头不被遮挡)的实现(10/7更新,封装了下)
- OGRE摄像机
- OGRE摄像机
- OGRE+Physx赛车游戏开发
- OGRE+Physx赛车游戏开发
- OGRE+Physx赛车游戏开发
- OGRE+Physx赛车游戏开发
- OGRE+Physx赛车游戏开发
- ogre中的摄像机
- Ogre摄像机Camera类
- Ogre摄像机Camera类
- Ogre中的摄像机
- Ogre中的摄像机
- Ogre摄像机Camera类
- OGRE摄像机方向总结
- OGRE摄像机方向总结
- ogre和physx二sdk整合笔记
- 用各种循环语句写增量
- 公共WiFi问题多 好事做不好谁该检讨
- 使用 JMeter 完成常用的压力测试
- 让程序员蛋疼的那些事儿
- 类中带默认参数的函数
- OGRE+PhysX仿魔兽世界摄像机
- 当所有人在说在中国玩类似kik应用会死的时候,微信却活了
- java线程同步
- linux下vpn服务器配置和管理
- Myeclipse svn插件修改服务器地址
- AnnotationAwareAspectJAutoProxyCreator is only available on Java 1.5 and higher
- Java内存与垃圾回收调优
- nyoj-5 Binary String Matching
- 建造者模式(生成器模式)