00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include <PVLE/3D/CameraShake.h>
00028 #include <PVLE/Util/Math.h>
00029 #include <PVLE/Util/Rand.h>
00030 #include <PVLE/Util/Util.h>
00031 #include <osg/Transform>
00032 #include <osgViewer/View>
00033 #include <osgGA/MatrixManipulator>
00034 #include <boost/cast.hpp>
00035
00036
00037
00038
00039 void CameraShakeParams::setAngles(const osg::Vec3f & dir) {
00040 float len = dir.length();
00041 if (len==0) {
00042
00043 angleTheta = 0;
00044 anglePhi = 0;
00045 return;
00046 }
00047 angleTheta = atan2(dir.y(), dir.x());
00048 anglePhi = acos(dir.z() / len);
00049 }
00050
00051 void CameraShakeParams::setAnglesRandom() {
00052 angleTheta = rand(0, 2*osg::PI);
00053 anglePhi = rand(0, osg::PI);
00054 }
00055
00056 class CameraShakeUpdateCallback : public osg::NodeCallback {
00057 public:
00058 CameraShakeUpdateCallback() : time0(-1) {}
00059 virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) {
00060
00061
00062 CameraShake * pCS = boost::polymorphic_downcast<CameraShake *>(node);
00063
00064 if (time0<0) time0 = nv->getFrameStamp()->getSimulationTime();
00065 pCS->curTime = nv->getFrameStamp()->getSimulationTime() - time0;
00066 pCS->updateCameras( osg::computeWorldToLocal(nv->getNodePath()).getTrans() );
00067 }
00068 protected:
00069 double time0;
00070 };
00071
00072
00073 CameraShake::CameraShake() : curTime(0), curNumHalfOscillation(0) {
00074 addUpdateCallback(new CameraShakeUpdateCallback);
00075 }
00076
00077 CameraShake::CameraShake(const CameraShakeParams & params) : params(params), curTime(0), curNumHalfOscillation(0) {
00078 addUpdateCallback(new CameraShakeUpdateCallback);
00079 }
00080
00081 CameraShake::CameraShake(const CameraShake & v, const osg::CopyOp& copyop) : params(v.params), curTime(0), curNumHalfOscillation(0) {
00082 addUpdateCallback(new CameraShakeUpdateCallback);
00083 }
00084
00085 CameraShake::~CameraShake() {
00086
00087 BOOST_FOREACH(CameraData & cameraData, vCameras) {
00088 if (!cameraData.pCamera.valid()) continue;
00089 setCamera(cameraData, osg::Vec3());
00090 }
00091 }
00092
00093 void CameraShake::updateCameras(const osg::Vec3f & pos) {
00094 const float baseTimeAmplitude = timedAmplitude();
00095 const float period = 1/params.frequency;
00096 const float oscillation = math_fmodf(curTime, period) / period;
00097
00098
00099 const float numHalfOscillation = static_cast<UINT>(curTime / period * 2);
00100 if (curNumHalfOscillation < numHalfOscillation) {
00101 curNumHalfOscillation = numHalfOscillation;
00102 params.angleTheta = math_fmodf(params.angleTheta + rand(-params.dispersionTheta, params.dispersionTheta), static_cast<float>(osg::PI*2));
00103 params.anglePhi = math_fmodf(params.anglePhi + rand(-params.dispersionPhi , params.dispersionPhi ), static_cast<float>(osg::PI));
00104 }
00105
00106
00107 BOOST_FOREACH(CameraData & cameraData, vCameras) {
00108 if (!cameraData.pCamera.valid()) continue;
00109 float curAmplitude = baseTimeAmplitude;
00110 if (params.distanceModel != CameraShakeParams::DIST_NONE) {
00111 float distance = (cameraData.pCamera->getViewMatrix().getTrans() - pos).length();
00112 if (distance > 1) curAmplitude /= params.distanceModel == CameraShakeParams::DIST_LINEAR ? distance : distance*distance;
00113 }
00114
00115 float oscillationAmplitude = sin(oscillation * osg::PI*2);
00116 curAmplitude *= oscillationAmplitude;
00117 float sinPhi = sin(params.anglePhi);
00118 osg::Vec3f newOffset(cos(params.angleTheta)*sinPhi*curAmplitude, sin(params.angleTheta)*sinPhi*curAmplitude, cos(params.anglePhi)*curAmplitude);
00119
00120 setCamera(cameraData, newOffset);
00121 }
00122 }
00123
00124 void CameraShake::setCamera(CameraData & cameraData, const osg::Vec3f & newOffset) {
00125 ASSERT(cameraData.pCamera.valid());
00126 osg::View * pView = cameraData.pCamera->getView();
00127 if (pView && pView->getCamera() == cameraData.pCamera.get()) {
00128
00129 osgViewer::View * pView2 = dynamic_cast<osgViewer::View *>(pView);
00130 if (pView2 && pView2->getCameraManipulator()) {
00131 osg::Matrix mat = pView2->getCameraManipulator()->getMatrix();
00132 mat.setTrans(mat.getTrans() + newOffset - cameraData.curOffset);
00133 pView2->getCameraManipulator()->setByMatrix(mat);
00134 }
00135 }
00136
00137 osg::Matrix & mat = cameraData.pCamera->getViewMatrix();
00138 mat.setTrans(mat.getTrans() + newOffset - cameraData.curOffset);
00139 cameraData.curOffset = newOffset;
00140 }