2007年10月25日星期四

解决了OGRE中渲染因为浮点数优化会崩溃的问题

使用的是OGRE 1.4.4版本。

当显示一个带有Alpha材质特效的图片时会遇到崩溃,在OgreRenderQueueSortingGrouping.h中172行

    // Different renderables, sort by depth
    Real adepth = a.renderable->getSquaredViewDepth(camera);
    Real bdepth = b.renderable->getSquaredViewDepth(camera); // This line
    if (adepth == bdepth)
    {
        // Must return deterministic result, doesn't matter what
        return a.pass < b.pass;
    }
错误是b中的内容非法。

排查以后,发现原来是这个函数(供STL比较使用)会返回不一致的结果,即第一次比较a & b说<,但是第二次会报>,结果导致STL混乱,错误的将vector中-1位的元素取出进行比较导致崩溃。

这个比较函数结果不一致的原因是renderable在计算距离时会cache到一个float中。而adepth == bdepth进行比较时,因为编译器进行了优化的缘故,实际将adepth这个float和刚刚调用b.renderable返回的double进行了比较,因为精度原因结果不相同。而第二次进行比较时,将renderable中的cache取回,都是float,所以比较结果相同。而进一步比较a.pass & b.pass时恰好和上一次比较结果相反。

Real adepth = a.renderable->getSquaredViewDepth(camera);
104FDF59 mov eax,dword ptr [ecx]
104FDF5B mov edx,dword ptr [esi]
104FDF5D mov eax,dword ptr [eax+20h]
104FDF60 push edx
104FDF61 call eax
104FDF63 fstp dword ptr [esp+10h]
Real bdepth = b.renderable->getSquaredViewDepth(camera);
104FDF67 mov ecx,dword ptr [edi]
104FDF69 mov edx,dword ptr [ecx]
104FDF6B mov eax,dword ptr [esi]
104FDF6D mov edx,dword ptr [edx+20h]
104FDF70 push eax
104FDF71 call edx
if (adepth == bdepth)
104FDF73 fld st(0)
104FDF75 fld dword ptr [esp+10h]
104FDF79 fucom st(1) 

104FDF7B fnstsw ax 

红色处为导致问题的地方。

OGRE 1.4.5解决了这个问题。方案:采用Math::equal进行比较。

没有评论:

发表评论