查看: 3130|回复: 18

一个精度的问题

[复制链接]

该用户从未签到

发表于 2009-5-21 14:41:15 | 显示全部楼层 |阅读模式
构造了一个简单的Geometry,显示一个管子
起初,顶点数组使用的Vec3Array(即float类型的顶点坐标)
使用缺省的TrackballManipulator观察
给一组较小的数时,能够正常显示出管子,移动和旋转相机时也没问题;
当给这组数加上一个较大的偏移量,如pos+=osg::Vec3d(10000000,10000000,10000000),静止状态下可以正常显示管子,移动相机时也没有问题,但旋转相机时看到的管子出现严重的断裂闪烁的情况,如图:

考虑可能是float顶点的精度不够导致的,所以改用Vec3dArray的顶点数组,但效果依旧
另外,只有在相机旋转时才发生闪烁,猜测是TrackballManpulator的旋转因子的精度不够,但看了下代码发现旋转使用的Quat的参数类型也是double型
请问这里在顶点数据很大时模型发生闪烁的现象,是什么原因导致的,如何解决?

btw:在使用Vec3dArray的顶点数组时,换用UFOManipulator,出现崩溃,发现是TriangleFunctor不支持Vec3d类型的顶点,这是不是说OSG中不能使用双精度的顶点呢?
IMG_0337.JPG

该用户从未签到

发表于 2009-5-21 17:21:40 | 显示全部楼层
OSG中当然支持双精度的顶点,默认也是这样。不过您可以在CMake编译的时候同时设置BoundingBox也使用双精度(它的默认是float),再试一下

该用户从未签到

 楼主| 发表于 2009-5-22 09:02:04 | 显示全部楼层
TriangleFunctor确实不支持双精度的顶点,而在场景求交使用TriangleFunctor时没有相应的判断,导致对使用双精度顶点的Drawable求交时的崩溃,这应该是OSG的一个BUG
我使用的是2.8版,不知道新的版本有没有修正这个问题

该用户从未签到

发表于 2009-5-22 09:11:27 | 显示全部楼层
LineSegment场景求交器我改写过,似乎不是TriangleFunctor的问题,而是算法本身有问题,我用osgModeling中的算法替换原来的就可以正确计算大地形的交点了。不过因为不知道原算法的问题在哪儿,没办法提交更改

该用户从未签到

 楼主| 发表于 2009-5-22 09:43:59 | 显示全部楼层
按照array的提示,去掉了config.h中的下列宏定义
//#define OSG_USE_FLOAT_BOUNDINGSPHERE
//#define OSG_USE_FLOAT_BOUNDINGBOX
使用双精度的包围盒
但是效果依然如故

该用户从未签到

发表于 2009-5-22 10:06:52 | 显示全部楼层
不是这么改的,要在CMake中关闭相关的选项,然后重新编译OSG。当然您的问题还要具体问题具体分析

该用户从未签到

 楼主| 发表于 2009-5-22 11:42:05 | 显示全部楼层
在CMake中关闭OSG_USE_FLOAT_BOUNDINGBOX的效果就是关闭config中的OSG_USE_FLOAT_BOUNDINGBOX宏定义,而这个宏定义决定了是使用双精度还是单精度的包围盒,这个从CMakeList.txt和以下代码内容可以看出来。
#ifdef OSG_USE_FLOAT_BOUNDINGBOX
typedef BoundingBoxf BoundingBox;
#else
typedef BoundingBoxd BoundingBox;
#endif

其实我的问题描述起来很简单,而且应该也是很普遍的问题:
(1)当一个简单的Geometry使用的顶点数据值很大时(超出了float精度,比如这样一个三角形((10000000,10000000,10000000), (10000001,10000000,10000000), (10000000,10000001,10000000))),无论使用单精度还是双精度的顶点类型,观察时会出现闪烁(至少在使用TrackballManipulator旋转观察时肯定会出现,静止时不会);
(2)当使用双精度顶点类型时,基于三角形的求交功能不能使用(导致崩溃)

该用户从未签到

 楼主| 发表于 2009-5-22 12:15:37 | 显示全部楼层
还有另一个问题,看了一个别人使用VPB生成的地球的模型,转成osg用记事本打开,发现里面的VertexArray使用的是Vec3Array,也就是单精度的顶点,可是顶点数值都很大(在地球半径的数量级),顶点如下:
VertexArray Vec3Array 2661
          {
            -6.37419e+006 157947 -6.21918e+006
            -6.36632e+006 -315702 -6.21937e+006
           ……
不过这个地球模型的显示效果却没有问题,在旋转时也不会出现闪烁,这是为什么呢?是否与使用了CoordinateSystemNode节点有关?
另外在用VPB生成球坐标的地球时,是否可以选用双精度的顶点类型?

[ 本帖最后由 indif 于 2009-5-22 12:17 编辑 ]

该用户从未签到

发表于 2009-5-22 12:28:56 | 显示全部楼层
float类型的取值范围是
3.40282e-038 到 3.40282e+038
所以您的闪烁问题不一定是单精度/双精度造成的,10000000只是一个再小不过的数值而已。

至于求交功能的问题,我以前已经注意到了,但是没办法验证现有算法的问题所在。如果可以的话,希望您能够给我一份可以说明问题的示例代码,我手头有更好的求交算法,看看能不能替代现有的

该用户从未签到

 楼主| 发表于 2009-5-22 12:50:28 | 显示全部楼层
float的取值范围没错,但取值范围与精度似乎没有直接的关系,float的精度是7位有效数字,也就是说对于地球半径6千公里这样的数量级,只能精确到米级,如6,374,191.5米这样的顶点坐标值,.5米已经是不能保证精度的了

该用户从未签到

 楼主| 发表于 2009-5-22 13:15:30 | 显示全部楼层
示例代码如下,可以运行看一下效果

#include <osgViewer\Viewer>
#include <osg\Material>
#include <osg\Geode>
#include <osg\Geometry>

osg::Node* createGeonode(const osg::Vec3d& base)
{
        osg::Geode* geode = new osg::Geode;
        osg::Geometry* geometry = new osg::Geometry;

        osg::Vec3d vertices[] =
        {
                osg::Vec3d(0, 0, 0) + base,
                osg::Vec3d(0, 0, 1) + base,
                osg::Vec3d(1, 0, 0) + base,
                osg::Vec3d(1, 0, 1) + base,
                osg::Vec3d(1, 1, 0) + base,
                osg::Vec3d(1, 1, 1) + base,
                osg::Vec3d(0, 1, 0) + base,
                osg::Vec3d(0, 1, 1) + base,
                osg::Vec3d(0, 0, 0) + base,
                osg::Vec3d(0, 0, 1) + base
        };
        geometry->setVertexArray(new osg::Vec3dArray(10, vertices));
        geometry->addPrimitiveSet(new osg:rawArrays(osg:rimitiveSet:UAD_STRIP, 0, 10));
        geode->addDrawable(geometry);

        osg::Material* material = new osg::Material;
        geode->getOrCreateStateSet()->setAttributeAndModes(material);

        return geode;
}

int main( int argc, char **argv )
{
        osgViewer::Viewer viewer;

        osg::Group* root = new osg::Group;

        root->addChild(createGeonode(osg::Vec3d(10000000,10000000,10000000)));

        viewer.setSceneData(root);

        return viewer.run();
}

该用户从未签到

发表于 2009-5-22 13:44:08 | 显示全部楼层
楼主看是否是这个原因:
OpenGL进行绘制的时候使用的是单精度浮点数,所以OSG将双精度浮点数表示的位置信息传递给OpenGL进行绘制时,就导致了精度损失,产生闪烁。
楼主看是否可以通过把偏移量移到模型视点矩阵中来解决这样的问题。

该用户从未签到

发表于 2009-5-22 16:52:17 | 显示全部楼层
确实是精度的问题,在直接使用定点列表的时候,数值过大或者过小(精度范围超过7)的时候,就会出现闪烁的情况。可以使用添加一个positionattitudetransform或者matrixtransform父节点+相对坐标来实现,不知道各位还有什么更好的方法没

该用户从未签到

 楼主| 发表于 2009-5-22 17:44:45 | 显示全部楼层
楼上两位的方法,在解决上面的示例代码的问题时,完全没有问题,现实中应该也是这样做的

但考虑这样一种情况:需要绘制地球表面一条很长的管道,长到上千公里,这时候无论取哪个点为基准点,相对坐标都会很大;这时候恐怕只能把这条管道分成几部分,分别取基准点,分别做变换了,但这样的话,分成几段的管子之间就不能保证无缝的连接了

该用户从未签到

 楼主| 发表于 2009-5-22 17:59:46 | 显示全部楼层
原帖由 xiaofeii 于 2009-5-22 13:44 发表
楼主看是否是这个原因:
OpenGL进行绘制的时候使用的是单精度浮点数,所以OSG将双精度浮点数表示的位置信息传递给OpenGL进行绘制时,就导致了精度损失,产生闪烁。


特意跟了一下,在使用Vec3dArray时,OSG调用glVertexPointer传递顶点数组给渲染管线时,type参数值确实是GL_DOUBLE,这个是没有问题的。
现在是使用双精度的顶点,双精度的矩阵,双精度的包围盒,可还是出现闪烁
OpenGL在使用双精度顶点时需要做什么特别的设置么?
哪位对这方面比较了解,还请不吝赐教啊

[ 本帖最后由 indif 于 2009-5-22 18:00 编辑 ]

该用户从未签到

发表于 2009-5-22 21:08:31 | 显示全部楼层
没有别的需要设置了

该用户从未签到

发表于 2009-5-23 07:57:50 | 显示全部楼层
原帖由 indif 于 2009-5-22 17:59 发表


特意跟了一下,在使用Vec3dArray时,OSG调用glVertexPointer传递顶点数组给渲染管线时,type参数值确实是GL_DOUBLE,这个是没有问题的。
现在是使用双精度的顶点,双精度的矩阵,双精度的包围盒,可还是出现闪烁 ...



即使type是GL_DOUBLE,但是GPU绘制的时候还是使用单精度去运算的,
即使在上层所有的运算都是用双精度,也避免不了被截取的困境。
貌似目前大部分的显卡进行GPU运算时都只能支持单精度浮点运算,
如果安装一块支持双精度运算的显卡应该可以解决这样的问题(http://www.thethirdmedia.com/Article/200802/show111620c31p1.html),
但是这样在配置比较低的机器上你的程序就跑不起来了。

该用户从未签到

发表于 2009-5-23 08:22:46 | 显示全部楼层
原帖由 indif 于 2009-5-22 17:44 发表
楼上两位的方法,在解决上面的示例代码的问题时,完全没有问题,现实中应该也是这样做的

但考虑这样一种情况:需要绘制地球表面一条很长的管道,长到上千公里,这时候无论取哪个点为基准点,相对坐标都会很大;这 ...


为什么不能做到无缝连接呢?如果从显示的角度看,应该没有问题吧?

使用局部坐标还是比较常规的做法,只是楼主需要做切割管道的琐碎工作。但是如果不做,就得使用双精度显卡,使GPU运算从单精度变成双精度,工作量加倍。说到底这个琐碎工作你不做,GPU只能多干活。

而且屏幕就那么大,使用双精度浮点数貌似没有太多实际意义。所有的绘制数据最后都要被opengl处理到视觉坐标系下一个长宽高都为2的立方体中,再进行拉伸移至屏幕坐标系,一般屏幕的大小也就是1024×768,不论大一点还是小一点,单精度浮点数已经够用了。

opengl本身也就是在各种坐标系之间变来变去,楼主再多做一次变换,应该问题不大吧,只是要多费点神。

该用户从未签到

发表于 2009-5-23 09:08:13 | 显示全部楼层
关注中!
您需要登录后才可以回帖 登录 | 注册

本版积分规则

OSG中国官方论坛-有您OSG在中国才更好

网站简介:osgChina是国内首个三维相关技术开源社区,旨在为国内更多的技术开发人员提供最前沿的技术资讯,为更多的三维从业者提供一个学习、交流的技术平台。

联系我们

  • 工作时间:09:00--18:00
  • 反馈邮箱:1315785073@qq.com
快速回复 返回顶部 返回列表