本系列博客是由扭曲45原创,欢迎转载,转载时注明出处,http://blog.csdn.net/cg0206/article/details/8300658
在一个物理步长内,碰撞处理可以被划分成narrow-phase和broad-phase两个阶段。在narrow-phase阶段计算一对形状的接触。假设有N个形状,直接使用蛮力进行计算,我们需要调用N*N/2次narrow-phase算法。
b2BroadPhase类通过使用动态树降低了管理数据方面的开销。这极大的降低了调用narrow-phase算法的次数。
一般情况下,你不需要直接和broad-phase打交道。Box2D来内部来创建和管理broad-phase。另外,b2BroadPhase是使用Box2D的模拟循环的思路来设计的,所以它可能不适合用于其他用途。
---摘自oh!coder的博客
Box2d中broad-phase用于计算pairs【相交记录】,执行容量查询和光线投射。主要还是调用上一节我们说的动态树进行数据方面的管理。首先,我们还是看看头文件b2BroadPhase.h中的定义部分。
//pair定义 struct b2Pair { int32 proxyIdA; //代理a int32 proxyIdB; //代理b int32 next; //下一个pair }; // broad-phase用于计算pairs,执行体积查询和光线投射 // broad-phase不会持续pairs.相反,它会汇报新的pairs。这取决于客户端是否用掉新的pairs和是否跟踪后续重叠。 class b2BroadPhase { public: //空节点代理 enum { e_nullProxy = -1 }; b2BroadPhase(); ~b2BroadPhase(); /************************************************************************** * 功能描述:创建一个代理,并用aabb初始化。pairs不会汇报直到UpdatePairs被调用 * 参数说明: allocator :soa分配器对象指针 userData :用户数据 * 返 回 值: (void) ***************************************************************************/ int32 CreateProxy(const b2AABB& aabb, void* userData); /************************************************************************** * 功能描述:销毁一个代理,任何pairs的删除都取决于客户端 * 参数说明: proxyId :代理id * 返 回 值: (void) ***************************************************************************/ void DestroyProxy(int32 proxyId); /************************************************************************** * 功能描述:移动一个代理。只要你喜欢可以多次调用MoveProxy, 当你完成后调用UpdatePairs用于完成代理pairs(在你的时间步内) * 参数说明: proxyId :代理id aabb :aabb变量 displacement :移动坐标向量 * 返 回 值: (void) ***************************************************************************/ void MoveProxy(int32 proxyId, const b2AABB& aabb, const b2Vec2& displacement); /************************************************************************** * 功能描述: 在下次调用UpdatePairs时,调用一个触发器触发它的pairs * 参数说明: proxyId :代理id * 返 回 值: (void) ***************************************************************************/ void TouchProxy(int32 proxyId); /************************************************************************** * 功能描述: 获取宽大的aabb * 参数说明: proxyId :代理id * 返 回 值: (void) ***************************************************************************/ const b2AABB& GetFatAABB(int32 proxyId) const; /************************************************************************** * 功能描述: 通过一个代理获取userData,如果id无效,返回NULL * 参数说明: proxyId :代理id * 返 回 值: 用户数据 ***************************************************************************/ void* GetUserData(int32 proxyId) const; /************************************************************************** * 功能描述: 测试宽大aabb的重复部分 * 参数说明: proxyIdA :A代理id proxyIdB :B代理id * 返 回 值: true :不重叠 false:重 叠 ***************************************************************************/ bool TestOverlap(int32 proxyIdA, int32 proxyIdB) const; /************************************************************************** * 功能描述: 获取代理数量 * 参数说明: (void) * 返 回 值: 代理数量 ***************************************************************************/ int32 GetProxyCount() const; /************************************************************************** * 功能描述: 更新pairs.这会对pair进行回调。只能添加pairs * 参数说明: callback :回调对象 * 返 回 值: (void) ***************************************************************************/ template <typename T> void UpdatePairs(T* callback); /************************************************************************** * 功能描述: 在重叠代理中查询一个aabb.每个提供aabb重叠的代理将会被回调类调用 * 参数说明: callback :回调对象类 aabb :aabb变量 * 返 回 值: (void) ***************************************************************************/ template <typename T> void Query(T* callback, const b2AABB& aabb) const; /************************************************************************** * 功能描述: 光线投射在树上的代理。 这依赖于回调被执行一个精确的光线投射在一个代理包含一个形状 * 参数说明: callback : 一个回调对象类,当被调用时,光线将会撒到每个代理中。 input :光线投射输入数据。这个光线从p1扩展到p1+maxFraction *(p2 - p1) * 返 回 值: (void) ***************************************************************************/ template <typename T> void RayCast(T* callback, const b2RayCastInput& input) const; /************************************************************************** * 功能描述: 获取嵌入树的高度 * 参数说明: (void) * 返 回 值: (void) ***************************************************************************/ int32 GetTreeHeight() const; /************************************************************************** * 功能描述: 获取嵌入树的平衡值 * 参数说明: (void) * 返 回 值: (void) ***************************************************************************/ int32 GetTreeBalance() const; /************************************************************************** * 功能描述: 获取嵌入树的质量,即是树的总aabbs周长与根节点aabb周长的比 * 参数说明: (void) * 返 回 值: 树的质量 ***************************************************************************/ float32 GetTreeQuality() const; private: //友元类 friend class b2DynamicTree; /************************************************************************** * 功能描述: 根据代理id添加代理到移动缓冲区中 * 参数说明: proxyId :代理id * 返 回 值: (void) ***************************************************************************/ void BufferMove(int32 proxyId); /************************************************************************** * 功能描述: 将代理移出移动缓存区 * 参数说明: proxyId :代理id * 返 回 值: (void) ***************************************************************************/ void UnBufferMove(int32 proxyId); /************************************************************************** * 功能描述: 查询回调函数 * 参数说明: proxyId :代理id * 返 回 值: true :表示正常回调 ***************************************************************************/ bool QueryCallback(int32 proxyId); //动态树声明 b2DynamicTree m_tree; //代理数量 int32 m_proxyCount; //移动的缓冲区 int32* m_moveBuffer; //移动缓冲区的总容量 int32 m_moveCapacity; //需要移动的代理数量 int32 m_moveCount; //pair缓冲区 b2Pair* m_pairBuffer; //pair缓冲区中的总容量 int32 m_pairCapacity; //pair数量 int32 m_pairCount; //查询代理id int32 m_queryProxyId; };
在这类中,可以看到b2BroadPhase将b2DynamicTree定义为友元类,也就是说b2DynamicTree每一个对象均可访问b2BroadPhase的任何成员,不管是否是私有的。同时我们又可以看到在b2BrodPhase类中,我们定义了个动态树对象m_tree,这样我们形成的好像是形成了一个环,但m_tree并不能访问b2DynamicTree中的私有变量。其他部分,不多说了,看注释。再来看内联函数的实现。
/************************************************************************** * 功能描述: 用于pairs的排序 * 参数说明: pair1:Pari对象引用 pair2: Pari对象引用 * 返 回 值: true : pair1较小 fasle:pair2较小 ***************************************************************************/ inline bool b2PairLessThan(const b2Pair& pair1, const b2Pair& pair2) { //比对pair的代理idA if (pair1.proxyIdA < pair2.proxyIdA) { return true; } //再比对代理idB if (pair1.proxyIdA == pair2.proxyIdA) { return pair1.proxyIdB < pair2.proxyIdB; } return false; } //根据代理id获取userData inline void* b2BroadPhase::GetUserData(int32 proxyId) const { return m_tree.GetUserData(proxyId); } //测试重叠 inline bool b2BroadPhase::TestOverlap(int32 proxyIdA, int32 proxyIdB) const { const b2AABB& aabbA = m_tree.GetFatAABB(proxyIdA); const b2AABB& aabbB = m_tree.GetFatAABB(proxyIdB); return b2TestOverlap(aabbA, aabbB); } //获取aabb inline const b2AABB& b2BroadPhase::GetFatAABB(int32 proxyId) const { return m_tree.GetFatAABB(proxyId); } //获取代理数量 inline int32 b2BroadPhase::GetProxyCount() const { return m_proxyCount; } //获取树的高度 inline int32 b2BroadPhase::GetTreeHeight() const { return m_tree.GetHeight(); } //获取树的平衡值 inline int32 b2BroadPhase::GetTreeBalance() const { return m_tree.GetMaxBalance(); } //获取树的质量 inline float32 b2BroadPhase::GetTreeQuality() const { return m_tree.GetAreaRatio(); } //更新pairs template <typename T> void b2BroadPhase::UpdatePairs(T* callback) { //重置pair缓存区 m_pairCount = 0; //执行查询树上所有需要移动代理 for (int32 i = 0; i < m_moveCount; ++i) { m_queryProxyId = m_moveBuffer[i]; if (m_queryProxyId == e_nullProxy) { continue; } // 我们需要查询树的宽大的AABB,以便当我们创建pair失败时,可以再次创建 const b2AABB& fatAABB = m_tree.GetFatAABB(m_queryProxyId); // 查询树,创建多个pair并将他们添加到pair缓冲区中 m_tree.Query(this, fatAABB); } //重置移动缓冲区 m_moveCount = 0; // 排序pair缓冲区 std::sort(m_pairBuffer, m_pairBuffer + m_pairCount, b2PairLessThan); // 发送pair到客户端 int32 i = 0; while (i < m_pairCount) { //在pair缓冲区中获取当前的pair b2Pair* primaryPair = m_pairBuffer + i; //根据相交记录 void* userDataA = m_tree.GetUserData(primaryPair->proxyIdA); void* userDataB = m_tree.GetUserData(primaryPair->proxyIdB); callback->AddPair(userDataA, userDataB); ++i; //跳过重复的pair while (i < m_pairCount) { b2Pair* pair = m_pairBuffer + i; if (pair->proxyIdA != primaryPair->proxyIdA || pair->proxyIdB != primaryPair->proxyIdB) { break; } ++i; } } // Try to keep the tree balanced. //m_tree.Rebalance(4); } //区域查询 template <typename T> inline void b2BroadPhase::Query(T* callback, const b2AABB& aabb) const { m_tree.Query(callback, aabb); } //光线投射 template <typename T> inline void b2BroadPhase::RayCast(T* callback, const b2RayCastInput& input) const { m_tree.RayCast(callback, input); }
关于这部分,就是对动态树中相关方法的封装,如果还有童鞋有疑问的话,不妨看看我的上一篇文章《Box2d源码学习<六>动态树的实现》,接下来来看看b2BroadPhase部分。
//构造函数,初始化数据 b2BroadPhase::b2BroadPhase() { m_proxyCount = 0; m_pairCapacity = 16; m_pairCount = 0; m_pairBuffer = (b2Pair*)b2Alloc(m_pairCapacity * sizeof(b2Pair)); m_moveCapacity = 16; m_moveCount = 0; m_moveBuffer = (int32*)b2Alloc(m_moveCapacity * sizeof(int32)); } //析构函数 b2BroadPhase::~b2BroadPhase() { b2Free(m_moveBuffer); b2Free(m_pairBuffer); } //创建一个代理 int32 b2BroadPhase::CreateProxy(const b2AABB& aabb, void* userData) { //获取代理id int32 proxyId = m_tree.CreateProxy(aabb, userData); //代理数量自增 ++m_proxyCount; //添加代理到移动缓冲区中 BufferMove(proxyId); return proxyId; } //销毁一个代理 void b2BroadPhase::DestroyProxy(int32 proxyId) { UnBufferMove(proxyId); --m_proxyCount; m_tree.DestroyProxy(proxyId); } //移动一个代理 void b2BroadPhase::MoveProxy(int32 proxyId, const b2AABB& aabb, const b2Vec2& displacement) { bool buffer = m_tree.MoveProxy(proxyId, aabb, displacement); if (buffer) { BufferMove(proxyId); } } //在下次调用UpdatePairs时,调用一个触发器触发它的pairs void b2BroadPhase::TouchProxy(int32 proxyId) { BufferMove(proxyId); } //根据代理id添加代理到移动缓冲区中 void b2BroadPhase::BufferMove(int32 proxyId) { //移动缓冲区过小,增容 if (m_moveCount == m_moveCapacity) { //获取移动缓冲区 int32* oldBuffer = m_moveBuffer; //将容量扩增为原来的2倍 m_moveCapacity *= 2; //重新申请移动缓冲区 m_moveBuffer = (int32*)b2Alloc(m_moveCapacity * sizeof(int32)); //拷贝旧的移动缓冲区内容到新的里面去,并释放旧的移动缓冲区 memcpy(m_moveBuffer, oldBuffer, m_moveCount * sizeof(int32)); b2Free(oldBuffer); } //添加代理id到移动缓冲区中 m_moveBuffer[m_moveCount] = proxyId; //自增 ++m_moveCount; } //移除移动缓存区 void b2BroadPhase::UnBufferMove(int32 proxyId) { //查找相应的代理 for (int32 i = 0; i < m_moveCount; ++i) { //找到代理,并置空 if (m_moveBuffer[i] == proxyId) { m_moveBuffer[i] = e_nullProxy; return; } } } //当我们聚集pairs时这个函数将会被b2DynamicTree:Query调用 bool b2BroadPhase::QueryCallback(int32 proxyId) { // 一个代理不需要自己pair更新自己的pair if (proxyId == m_queryProxyId) { return true; } // 如果需要增加pair缓冲区 if (m_pairCount == m_pairCapacity) { //获取旧的pair缓冲区,并增加容量 b2Pair* oldBuffer = m_pairBuffer; m_pairCapacity *= 2; //重新申请pair缓冲区,并拷贝旧缓冲区中的内容 m_pairBuffer = (b2Pair*)b2Alloc(m_pairCapacity * sizeof(b2Pair)); memcpy(m_pairBuffer, oldBuffer, m_pairCount * sizeof(b2Pair)); //释放旧的pair缓冲区 b2Free(oldBuffer); } //设置最新的pair //并自增pair数量 m_pairBuffer[m_pairCount].proxyIdA = b2Min(proxyId, m_queryProxyId); m_pairBuffer[m_pairCount].proxyIdB = b2Max(proxyId, m_queryProxyId); ++m_pairCount; return true; }
通过源代码我们可以看到,它的实现主要靠移动缓冲区(m_moveBuffer)和pair缓冲区(m_pariBuffer)。构造函数b2BroadPhase()主要是申请这两个缓冲区,析构函数~b2BroadPhase()释放这两个缓冲区,创建一个代理函数CreateProxy()主要添加代理到移动缓冲区,销毁代理函数DestroyProxy主要是销毁一个在移动缓冲区的代理,MoveProxy()、TouchProxy()、BufferMove()均是在移动缓冲区中添加代理,UnBufferMove()是在移动缓冲区中移除代理,QueryCallback()是对pair缓冲区的操作。
突然我们心中有一个疑问,这两个缓冲区各自操作各自的,通过这段代码我们看不到任何的联系,它们到底是如何通信的呢?请先大家思考下。。。
好了,大家知道了吗?有人猜到是通过UpdatePairs函数实现的,这是正确的,但具体的还是通过动态树中的Query函数来实现的,我们不妨回顾一下updatepairs中的代码段。//执行查询树上所有需要移动代理 for (int32 i = 0; i < m_moveCount; ++i) { m_queryProxyId = m_moveBuffer[i]; if (m_queryProxyId == e_nullProxy) { continue; } // 我们需要查询树的宽大的AABB,以便当我们创建pair失败时,可以再次创建 const b2AABB& fatAABB = m_tree.GetFatAABB(m_queryProxyId); // 查询树,创建多个pair并将他们添加到pair缓冲区中 m_tree.Query(this, fatAABB); }
有人也许会说,这段代码我们只看到移动缓冲区(m_moveBuffer),看不出来与pair缓冲区(m_pariBuffer)有任何关系,它们怎么产生联系的呢?注意m_tree.Query(this,fatAABB)这句代码和它传递的参数,this表示当前类的对象,fatAABB表示移动缓冲区中一个代理的AABB,存储了代理的信息。我们再回顾一下query函数:
/************************************************************************** * 功能描述:查询一个aabb重叠代理,每个重叠提供AABB的代理都将回调回调类 * 参数说明:callback :回调对象 aabb :要查询的aabb * 返 回 值:aabb对象 ***************************************************************************/ template <typename T> void Query(T* callback, const b2AABB& aabb) const;再看Query函数中的代码片段
//是否成功 bool proceed = callback->QueryCallback(nodeId); if (proceed == false) { return; }看这句代码bool proceed = callback->QueryCallback(nodeId); 此处的callback就是刚刚传进去的this,也就是说我们调用的QueryCallback也就是b2BroadPhase::QueryCallback(int32 proxyId)函数。到此处相信大家已经明白了。
ps:
以上文章仅是一家之言,若有不妥、错误之处,请大家多多之出。同时也希望能与大家多多交流,共同进步。
手机的应用处理器是针对手机的某些特定类型的应用所开发的处理器。可以将应用处理器分为三大类型,一类是全面型的,一类是多媒体型的,再有一类是单一媒体型的。全面型的既要有多媒体应用处理器的功能,同时也能运行复杂的类似Linux之类的操作系统,这样的厂家通常有SAMSUNG、ST、TI、 RENESAS和Marvell。多媒体型指那些处理媒介超过两种的处理器,通常是图像、声音、视频、3D图形之类的。大多数应用处理器都是这一类的。单一型只处理静止图像或者声音。
应用处理器的出现源自手机应用的不断创新和发展。对大多数厂家来说,他们都在手机平台设计上累积丰富的经验和知识产权。这些平台都是早年只针对通讯,对于通讯之外的应用,这些平台都无能为力。因此应用处理器出现了。
应用处理器最大的好处在于完全独立在手机通讯平台之外,灵活方便,缩短设计流程,最大化利用已有的经验和IP。照相手机的出现,造就了一批专门处理照相后段的应用处理器厂家。而手机平台厂家都是SoC的行家,平台厂家在1-2年内将处理照相后段的JPEG编解码功能集成在基带IC中,这就导致了一大批JPEG编解码功能的应用处理器厂家进入低谷期。也就是2006年,这些厂家的收入大幅度下滑,出货量锐减。
不过手机的新应用催生了另一波应用处理器的高潮。这些应用包括复杂操作系统、移动电视、高品质3D图像、300万以上照相、智能化、GPS、高分辨率拍摄视频流等。不过应用处理器厂家们需要注意了,现在部分平台厂家已经将支持500万像素,30 fps, H.264, MPEG4, H.263 和 WMV9视频播放,VGA分辨率输出,16比特颜色深度集成在基带IC里,这些高性能基带IC预计在2011年大量进入手机应用。届时,应用处理器厂家又要遭遇一次下滑。目前TI、Qualcomm、MTK均有支持5M像素的基带IC产品,特别Qualcomm的Snapdragon更是支持sensor到12M像素的主频达1GHz的基带IC。东芝TG01、宏碁 F1 均是基于此平台的高性能手机。
目前还存在这样一种设计思路,就是用ULC(Ultra Low Cost)手机的设计方案加应用处理器,尤其是英飞凌的ULC手机方案。这对应用处理器来说是一片可观的市场空间。
MTK介绍
MTK是联发科技股份有限公司的英文简称,英文全称叫MediaTek。其创立于1997年,是世界顶尖的IC专业设计公司,位居全球消费性IC片组的领航地位。
2007年9月10日,联发科(MTK)宣布与ADI签署协议,以现金约3.5亿美元取得ADI旗下Othello和SoftFone手机芯片产品线相关的有形及无形资产以及团队。通过此项交易案,MTK的无线通讯部门将获得一支近400位具有丰富产品开发及客户服务经验的专业团队;扩大全球各地的客户群;增加新的手机基带和射频芯片产品包括GSM、GPRS、EDGE、WCDMA和TD-SCDMA芯片以丰富其现有的产品组合。
MTK目前在大陆占有超过40%的手机基带芯片份额,而ADI在大陆手机基带芯片市场的占有率也近10% 。因此在手机领域整合后的MTK已拿下大陆市场近50%的基带芯片份额。
MTK平台发展及手机基带芯片功能介绍:
MT6205、MT6217、MT6218、MT6219、MT6223、MT6225、MT6226、MT6227、MT6228、MT6229、MT6230、MT6235、MT6238、MT6239均为基带芯片,所以芯片均采用ARM7的核。
MT6205只有GSM的基本功能,不支持GPRS、WAP、MP3等功能。
MT6218为在MT6205基础上增加GPRS、WAP、MP3功能。
MT6217为MT6218的cost down方案,与MT6128 PIN TO PIN,只是软件不同而已。
MT6219为MT6218上增加内置1.3M camera处理IC,增加MP4功能。
MT6223为MTK的低端处理器,其中的C版本可以软件支持10万像素的sensor,D版本则没有camera接口。
MT6225内置0.3M camera处理IC。
MT6226为MT6219 cost down产品,内置0.3M camera处理IC。
MT6226M为MT6226高配置设计,内置的是1.3M camera处理IC。
MT6227与MT6226功能基本一样,PIN TO PIN,内置2.0M camera处理IC。
MT6228比MT6227增加TV OUT功能,内置3.0M camera处理IC,支持支持GPRS、WAP、MP3、MP4。
MT6229内置3.0M camera处理IC。
MT6230内置1.3M camera处理IC。
MT6235内置2.0M camera处理IC。
MT6238内置3.0M camera处理IC。
MT6239内置5.0M camera处理IC,
从MT6226后软件均可支持网络摄像头功能,也就是说你的机子可以用于QQ视频。
MTK收购ADI继承的基带处理器型号则有如下几种:
MT6A01、AD6726 (Atlas2HULC)、AD6723 (LeMans65)、AD6900 (LeMans)为GSM/GPRS的基带处理器带有camera接口。
AD6724 (AtlasULC)则为低端的GSM/GPRS基带处理器并不带camera接口。
AD6905 (Laguna)、AD6903(LeMans-LCR+) 均为支持TD-SCDMA的基带处理器,并带有camera的接口。
Marvell介绍
2006年11月,Marvell以6亿美元整体收购Intel XScale手机及手持设备芯片业务。也就是说,目前英特尔手机手持业务已经被全部转到Marvell了,其中包括应用处理器,通信处理器和其它配套软件。如PXA 3xx为应用处理器,而PXA90x则属于通信处理器。
Marvell手机及手持设备业务方面的PXA系列产品产品,从英特尔的Strong ARM到PXA 255, PXA 270系列,再到Marvell的PXA 3xx系列应用处理器,都同时具备低功耗和高性能两大特点。
2007年12月份Marvell发布了PXA 3XX系列,如PXA 300(3M sensor)、PXA 310(5M sensor)、PXA 320(3M sensor)等。其中的PXA 312已经成为了目前Windows Mobile智能手机领域最强大的CPU,被三星i908E等旗舰级产品所采用。此外PXA 310芯片还被多款TD手机所采用,其中就包括中兴推出的第一款支持HSDPS的Windows Mobile智能TD手机U990(2M sensor)和三星的WM智能TD手机i688(3M sensor 自动对焦)。由于PXA 310这样的应用芯片设计非常灵活,因此可以根据运营商的需求加装各种IP。举个例子来说,上述的三星i688和U990等产品都采用了同一款Marvell芯片,但在加装了不同的IP之后,它们就可以分别支持目前的TD-SCDMA和未来的HSDPA,而至于CMMB、GPS等功能,也可以通过不同的定制组合来解决。
列举一些采用Marvell处理器芯片的手机厂商及产品型号如下:
三星 智能旗舰i908E(5M sensor自动对焦) 、i788(2M sensor)、i688(3M sensor 自动对焦);
黑莓 BOLD 9000(2M sensor);
联想 ET700(2M sensor);
琦基 U8(2M sensor);
中兴 U990(2M sensor)等。
Mtekvision介绍
Mtekvision 成立于1999 年1 月,该公司最早开发PC 和MP3 用的摄像头,不过在2000 年,宽带普及率低,MP3 也不多见。
在2001 年3 月,该公司开发出全球第一款手机用的照相控制IC,从此一飞冲天,2002-2005 年的3 年内收入增1453%。Mtekvision在2005 年德勤评选的亚太地区高科技增长500 强企业排名第十四,也是IC 设计公司类第一名,并 多次荣获韩国最佳50 强中小企业。
国家扶持是Mtekvision 成功的关键之一,韩国的中小企业委员会多次协助其获得风险投资,韩国工业技术协会与其联合技术开发。最关键的还是三星的帮助,三星最成功的机型D508 采用了该公司的照相控制IC,D508 超过1 千万台的销量使该公司业绩飞跃。三星的经典机型E-700 和E-720 也采用该公司的照相控制IC,三星为其贡献了80%的收入。
其产品型号有CSP(Camera Signal Processor):MV3320(世界上第一款手机照相控制IC)、MV3020(2M Sensor)、MV3315(2M Sensor)、MV3018(VGA Sensor)、MV3019(Mega Sensor)、MV9333、MV9517、MV9331、MV9319、MV9317(世界上第一款5M 像素带实时图像压缩功能的照相信号处理器)、MV9315;MMP(Multi-Media Processor):MV8750(5M sensor)、MV8510、MV8000(SMIA interface)、MV8720、MV8650、MV8630、MV8620、MV8508、MV8602(5M sensor)等。
本系列博客是由扭曲45原创,欢迎转载,转载时注明出处,http://blog.csdn.net/cg0206/article/details/8300800
Box2d中每种物体它都是要有形状的,关于形状的是如何定义和实现的,我们今天就来说说。要将一个形状描述出来,我们必须知道它的定义,不禁要问形状是什么呢?用来干什么的呢?形状是几何体,用来给物体(body)定型的。同时形状可以在物理模拟中独立使用,你就可以对形状进行各种操作。
父形状的实现只有一个b2Shape.h文件,我们就来看下它是怎么实现的。
// 这个拥有质量,用于形状的计算 struct b2MassData { // 形状的质量,通常单位是kg float32 mass; //形状的质心到形状的原点 b2Vec2 center; //形状的转动惯量 float32 I; }; //一个形状用于碰撞检测。只要你喜欢,你可以创建一个形状。 // 在b2World世界中,形状用于模拟,当创建一个b2Fixture时将被自动创建。 //形状类将被封装成一个或多个子形状类 class b2Shape { public: //形状类型 enum Type { e_circle = 0, //圆形 e_edge = 1, //边缘形状 e_polygon = 2, //多边形 e_chain = 3, //链形状 e_typeCount = 4 //形状总数 }; virtual ~b2Shape() {} /************************************************************************** * 功能描述:用soa块分配器克隆一个具体的形状 * 参数说明: allocator :soa分配器对象指针 * 返 回 值: 形状指针 ***************************************************************************/ virtual b2Shape* Clone(b2BlockAllocator* allocator) const = 0; /************************************************************************** * 功能描述:获取孩子形状类型,你可以使用它去创建形状 * 参数说明: (void) * 返 回 值: 孩子形状个数 ***************************************************************************/ Type GetType() const; /************************************************************************** * 功能描述:获取形状的孩子元素的数量, 主要用于chainShape中,到时我们再谈 * 参数说明: (void) * 返 回 值: 孩子元素的数量 ***************************************************************************/ virtual int32 GetChildCount() const = 0; /************************************************************************** * 功能描述:在这个形状中测试这个点的密封性,只适合用于凸的形状 * 参数说明: xf : 形状的变换 p : world坐标中的一个点 * 返 回 值: true : 密封 false:敞开 ***************************************************************************/ virtual bool TestPoint(const b2Transform& xf, const b2Vec2& p) const = 0; /************************************************************************** * 功能描述:投射一束光到一个孩子形状中 * 参数说明: output :输出光线投射的结果 input :输入光线投射 transform :变换应用到此形状中 childeIndex :孩子形状索引 * 返 回 值: true : 成功 false:失败 ***************************************************************************/ virtual bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, const b2Transform& transform, int32 childIndex) const = 0; /************************************************************************** * 功能描述:给出一个变换,计算一个孩子形状的轴对齐包围盒(aabb) * 参数说明: aabb : 孩子形状的aabb指针 xf : 一个变换的引用 childIndex : 孩子的索引值 * 返 回 值: (void) ***************************************************************************/ virtual void ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const = 0; /************************************************************************** * 功能描述:用它的大小和密度计算形状的质量 * 参数说明: massData : 计算形状的质量 density : 密度 * 返 回 值: (void) ***************************************************************************/ virtual void ComputeMass(b2MassData* massData, float32 density) const = 0; //形状类型 Type m_type; //半径 float32 m_radius; }; //获取形状类型 inline b2Shape::Type b2Shape::GetType() const { return m_type; }我们可以看到shape中基本上都是虚函数,是没有实现的。shape中定义了以下几个函数:
1、克隆一个形状
2、获取孩子形状类型
3、获取形状的孩子元素的数量
4、投射一束光到一个孩子形状中
5、计算一个孩子形状的轴对齐包围盒(aabb)
6、计算形状的质量
7、测试形状中点的密封性。
还有想问大家一点关于虚函数问题,为什么这里析构函数要定义为虚函数?如果不定义为虚函数又会怎样?有没有其它隐患?希望大家思考一下,有时间的话我们再说一下。
其它具体的定义请见注释,子形状的实现将于下篇文章与大家见面。各位,晚安。。。
ps:
以上文章仅是一家之言,若有不妥、错误之处,请大家多多指出。同时也希望能与大家多多交流,共同进步。