耗时一个多月,完成了放顶煤、薄煤层液压支架仿真程序的编写。
主要思想:
偶也是菜鸟,刚开始想用骨骼动画实现,但是没有人可给帮我做机械的骨骼动画,只好放弃。
第二种思路,想用Max导出的关键帧动画来实现,每个支架有非常多的动作,十几种,每种动作与其他动作都有可能同时发生,用Max做好关键帧动画之后,导出时分段导出动画,对每个动作分别进行导出,导出后导入程序,当两个动作同时播放时发现模型裂了,如图:
,纠结起原因,读OgreMax导入场景的代码,发现当播放两个动作时,此时模型的每个mesh都做了两次位移、旋转、等等,肯定会裂开,同时播放几个动画,此时模型就会位移几次~~,研究了将近一周的时间,美工没有用过OgreMax,加上我是个菜鸟~~最后多方求友,不得不放弃,(如果那位网友知道如何避免这个问题,请不吝赐教)。
最后不得不采用控制节点,使用节点动画来实现,通过一个controller来实现,因为最终模型需要通过硬件来控制,控制器与PC是通过串口进行通讯的,所以本程序共分为三个部分:
1、通讯部分
通过串口,不同的支架传输不同字节长度的数据,根据数据的某一位控制支架做相应的动作。在数据传输过程中使用CRC校验。
示例代码如下:
short usDataLen)2: {/* 高CRC 字节初始化 *//* 低CRC 字节初始化 *//* CRC 循环中的索引 *//* 传输消息缓冲区 */7: {/* 计算CRC */9: uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex] ;10: uchCRCLo = auchCRCLo[uIndex] ;11: }return (uchCRCHi << 8 | uchCRCLo) ;13: }14://构造液压支架通信命令char>& result)17: {18: result.resize(cnt+3);19: result[0] = 0xaf;20:21: memcpy(&result[1], buf, cnt);22:char *)&result[0], cnt+1);24: result[cnt + 1] = crc >> 8;25: result[cnt + 2] = crc & 0xff;26:return cnt+3;28: }29://CRC校验char>& result)32: {//if(cnt != 9)//{//}38:char *)(buf+0), cnt-2);char *)(buf+1 + cnt-3));41: send_crc <<= 8;char *)(buf+2 + cnt-3));if(send_crc != recv_crc)44: {));return -1;48: }49:50: result.resize(cnt-3);51: memcpy(&result[0], buf+1, cnt-3);52:return cnt-3;54: }2、支架组装,定义部分
此部分将支架组装,使用了一种极其笨拙的方法,将支架的各个部分使用OgreMax导出后,然后根据OgreMax导出的scene文件的坐标值,然后在程序中组装支架。定义的变量相当繁琐,有很大缺陷,当换一个支架的时候,程序的数据需要重写。就是根据支架的结构创建支架,将支架的各个部分一一组装起来。代码如下:
1: mSupportRoot = mSManager->getRootSceneNode()->createChildSceneNode(mName);, Vector3(0, 0, 0));3://推溜节点, Vector3(-1.18005, 0.115254, 0)););7: mMoveSupport->attachObject(e);8:, Vector3(-1.03653, -0.0424172, 0)););11: mScraper->attachObject(e);12: mScraper->setVisible(mIsShowScraper);13://底座节点););17: mBase->attachObject(e);, Vector3(-1.05936, 0.141, 0));19://抬底节点, Vector3(-1.26348, 0.30187, 0)););23: mLiftBase->attachObject(e);24://下立柱节点, Vector3(-1.07193, 0.538018, 0)););28: mDownPillar->attachObject(e);29: mDownPillar->setOrientation(0.989742, 0, 0, 0.142869);30://上立柱节点, Vector3(0, 1.181672, 0)););36: mUpPillar->attachObject(e);//mUpPillar->setOrientation(0.997184, 0, 0, 0.0749965);38://顶梁节点, Vector3(0.00674, -0.00362, 0));41: mTopBeamAxis->roll(Radian(Math::DegreesToRadians(-17)));););/*0.915483*/0.715483, -0.10226, 0));//mTopBeamTrack->attachObject(e);//mTopBeamTrack->setScale(0.001, 0.001, 0.001););50: mTopBeam->attachObject(e);51://恻护节点, Vector3(-0.00456, -0.00654, 0)););55: mSideGuard->attachObject(e);56://平衡千斤顶顶梁部分, Vector3(0.435347, -0.00176, 0));59: mShieldJack2Axis->setInheritOrientation(false););61: mShieldJack2->setOrientation(0.907374, 0, 0, 0.420324););63: mShieldJack2->attachObject(e);64://掩护梁节点, Vector3(0.715483, -0.01226, 0));67: mShieldBeamAxis->setOrientation(0.909066, 0, 0, -0.416652);//mShieldBeamAxis->roll(Radian(Degree(-50))););70: mShieldBeam->translate(0.35, 0.05, 0, Node::TransformSpace::TS_LOCAL););72: mShieldBeam->attachObject(e);//mShieldBeam->setVisible(false);74://掩护梁恻护节点, Vector3(0, 0, -0.503772)););78: mShieldSideGuard->attachObject(e);79://平衡千斤顶掩护梁部分节点, Vector3(0.1 ,-0.104284, 0));83: mShieldJack1Axis->setInheritOrientation(false);););86: mShieldJack1->attachObject(e);87:88:89: mShieldJack2->setAutoTracking(true, mShieldJack1Axis, Vector3::NEGATIVE_UNIT_Y);90: mShieldJack1->setAutoTracking(true, mShieldJack2Axis, Vector3::UNIT_Y);91:, Vector3(0.3517407, -0.098777, 0));, Vector3(0.0517407, -0.178777, 0));//mFrontRodTarget->attachObject(e);//mFrontRodTarget->setScale(0.0005, 0.0005, 0.0005);, Vector3(-0.579555, 0.413417, 0));););101: mFrontRod->attachObject(e);102:103:, Vector3(0.68769, -0.05, 0));, Vector3(0.00769, -0.05, 0));//mBackRodTarget->attachObject(e);//mBackRodTarget->setScale(0.0005, 0.0005, 0.0005);, Vector3(-0.201678, 0.140705, 0));););113: mBackRod->attachObject(e);114:115: mFrontRod->setAutoTracking(true, mFrontTargetTo, Vector3::UNIT_Y);116: mBackRod->setAutoTracking(true, mBackRodTo, Vector3::UNIT_Y);3、动画控制部分
对于每个动作创建一个动画控制器(controller),根据动作的速度与每一帧的时间控制支架做动作,创建的动画控制器为createFrameTimePassthroughController,这样就可以使用frame time传递给控制器函数(controller function)。
为每个动作定义一个控制器,控制其中对每个支架的各个部分进行控制。在处理多个部分联动的时候可能要稍微注意一下,需要注意各部分的关系,本程序中在液压支架进行升柱、降柱的时候进对液压支架的顶梁、掩护梁、后连杆、底座、立柱进行了一系列余弦定理的处理,保证其动作的准确性。代码如下:
public://上立柱降柱动画控制器//上立柱升柱动画控制器//下立柱降柱动画控制器//下立柱升柱动画控制器6://移架动画控制器//推溜动画控制器9://伸平衡动画控制器//收平衡动画控制器12:13: MonitorControllerValuePtr mTopAngleCalController; //顶梁角度控制器
1: ControllerManager &contMgr = ControllerManager::getSingleton();2://上立柱降柱动画控制器this));5: contMgr.createFrameTimePassthroughController(mTopPillarDownController);6: MonitorControlDest *pController = (MonitorControlDest *)mTopPillarDownController.get();7://上立柱升柱动画控制器//mTopPillarUpController = MonitorControllerValuePtr(new MovePillarUp(mUpPillar, 1.49607, mSpeedPillarUp, this));this));11: contMgr.createFrameTimePassthroughController(mTopPillarUpController);12://下立柱降柱动画控制器this));15: contMgr.createFrameTimePassthroughController(mDownPillarDownController);16://下立柱升柱动画控制器this));19: contMgr.createFrameTimePassthroughController(mDownPillarUpController);20://伸平衡动画控制器this));23: contMgr.createFrameTimePassthroughController(mBalancePullController);24://收平衡动画控制器this));27: contMgr.createFrameTimePassthroughController(mBalancePushController);28://推流动画控制器new MoveScraperFront(mMoveSupport, mFulcrum, 2.0, mSpeedPush));31: contMgr.createFrameTimePassthroughController(mScraperPushController);32://移架动画控制器new MoveScraperFront(mFulcrum, mMoveSupport, -1.18005, mSpeedMove));35: contMgr.createFrameTimePassthroughController(mBaseFrontController);36:this));38: contMgr.createFrameTimePassthroughController(mTopAngleCalController);
各个控制器,控制函数定义代码:
public Ogre::ControllerValue<Ogre::Real>2: {public:4: MonitorControlDest() : mControlValue(0), mControlFlow(0){}5://设置控制值void setControlValue(Ogre::Real controlValue)8: {9: mControlValue = controlValue;10: }11://得到控制值13: Ogre::Real getControlValue()14: {return mControlValue;16: }17://设置动画控制器void setControlFlow(ControlFlow *pFlow)20: {21: mControlFlow = pFlow;22: }23://得到动画控制器25: ControlFlow* getControlFlow()26: {return mControlFlow;28: }protected://控制值//流程动画控制器32: };33://收平衡动画控制器public MonitorControlDest36: {public:38: PushBalance(Ogre::SceneNode *node, Ogre::Real stopPos, Ogre::Real speed, ThinSeamSupport *support)39: : mNode(node), mStopPos(stopPos), mSpeed(speed), mSupport(support)40: {41:42: }43://得到当前的值const46: {if(mNode)return mNode->getOrientation().getPitch().valueDegrees();return 0;50: }51://设置当前值void setValue(Ogre::Real value);protected://被控制对象//停止位置//速度//液压支架对象59: };
程序运行如下: