Dear All:
這陣子因為工作上的需要開始看Irrlicht這套Open Source的Engine,就使用上來說,真的不得不佩服它直覺與乾淨的API介面,比起OGRE你會感覺OGRE是Ogre。當然Irrlicht也不是沒缺點,最嚴重就是Animation 、Collision與Rendering這三個系統。首先,Animation沒有GPU的Skin mesh,一切交由CPU、Collision System效能過慢,而Rendering 架構上沒特別為Shader做設計,還停留在Fixed Render Pipeline時代。
OK!今天要記錄的Tuning在Collision System,重點如下:
問題:
Irrlicht的Collision在每次碰撞前,都從Selector裡把碰撞層的所有三角形拷貝出來,過程中順便做Local to World Space的轉換,若面數量少還好,要是以上千面來算就可觀了!小弟用Intel Core2 i3做實驗,每個Frame對一個1250面的模型做50次的線段碰撞,FPS竟然低於100以下,這對於要拿Irrlicht寫遊戲的人來說,根本就不堪使用。
解法:
關鍵就發生在CSceneCollisionManager::getCollisionPoint這個函式,這函式做了以上所描述的事情,那該怎麼改呢?其實不難,眼尖的你因該已經心裡有譜了,問題出在“拷貝”與“空間轉換”,上千個頂點的模型來說這算量是非常大的,所以就是要tuning這兩點。
- 空間轉換:我們只需要把線段轉換至Model的Local Sapce,去做碰撞就可解決將所有點轉換至World Space的問題了!
- 拷貝:我們只是單純的對碰撞層的Model做碰撞,並不會修改到資料本身,因此是可以保證資料不被修改的安全性。
bool getCollisionPoint(const core::line3d & ray, const core::matrix4& matWorld, ITriangleSelector* selector, core::vector3df& outIntersection, core::triangle3df& outTriangle, ISceneNode*& outNode) { if (!selector) { _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; return false; } s32 cnt = selector->getTriangleCount(); const core::vector3df linevect = ray.getVector().normalize(); core::vector3df intersection; f32 nearest = FLT_MAX; bool found = false; const f32 raylength = ray.getLengthSQ(); const f32 minX = core::min_(ray.start.X, ray.end.X); const f32 maxX = core::max_(ray.start.X, ray.end.X); const f32 minY = core::min_(ray.start.Y, ray.end.Y); const f32 maxY = core::max_(ray.start.Y, ray.end.Y); const f32 minZ = core::min_(ray.start.Z, ray.end.Z); const f32 maxZ = core::max_(ray.start.Z, ray.end.Z); for (s32 i=0; i const core::triangle3df& triangle = (*selector->getTriangles())[i]; if(minX > triangle.pointA.X && minX > triangle.pointB.X && minX > triangle.pointC.X) continue; if(maxX < triangle.pointA.X && maxX < triangle.pointB.X && maxX < triangle.pointC.X) continue; if(minY > triangle.pointA.Y && minY > triangle.pointB.Y && minY > triangle.pointC.Y) continue; if(maxY < triangle.pointA.Y && maxY < triangle.pointB.Y && maxY < triangle.pointC.Y) continue; if(minZ > triangle.pointA.Z && minZ > triangle.pointB.Z && minZ > triangle.pointC.Z) continue; if(maxZ < triangle.pointA.Z && maxZ < triangle.pointB.Z && maxZ < triangle.pointC.Z) continue; if (triangle.getIntersectionWithLine(ray.start, linevect, intersection)) { const f32 tmp = intersection.getDistanceFromSQ(ray.start); const f32 tmp2 = intersection.getDistanceFromSQ(ray.end); if (tmp < raylength && tmp2 < raylength && tmp < nearest) { nearest = tmp; outTriangle = triangle; outIntersection = intersection; outNode = selector->getSceneNodeForTriangle(i); found = true; } } } if( found ) { matWorld.transformVect( outTriangle.pointA, outTriangle.pointA ); matWorld.transformVect( outTriangle.pointB, outTriangle.pointB ); matWorld.transformVect( outTriangle.pointC, outTriangle.pointC ); matWorld.transformVect( outIntersection, outIntersection ); } _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; return found; }
沒有留言:
張貼留言