扭曲的场景有两套Geodes

时间:2014-08-29 21:52:51

标签: c++ opengl openscenegraph

我想将几个对象组合成一个场景图。

  1. Street继承自Geode,并且有Geometry子绘图,由GL_LINE_STRIP组成。

  2. Pointer继承自PositionAttitudeTransform并包含Geode,其中包含两个Geometry多边形。

  3. 当我向Group添加一堆Streets时,它看起来很好。当我只将指针添加到Group时,它看起来也很好。但是,如果我以某种方式将它们都放在场景中,那么第二个就搞砸了。看两张照片。

    One view when the streets are first

    在上图中,街道网络符合要求,在下图中,指针符合要求。

    One view when the pointer is first

    我很感激任何帮助!如果您需要查看代码,请告诉我,我会更新我的问题。

    更新1:由于目前尚未发生任何事情,因此产生此现象所需的代码量最少。我没有任何问题地把两个指针放在一起,所以我开始怀疑我把街道搞错了......下次更新将是一些街道代码。

    更新2:代码现在包含街道绘图代码。

    更新3:代码现在还包含指针绘图代码和街道绘图 代码已经简化。

    // My libraries:
    #include <asl/util/color.h>
    using namespace asl;
    
    #include <straph/point.h>
    #include <straph/straph.h>
    using namespace straph;
    
    // Standard and OSG libraries:
    #include <utility>
    #include <boost/tuple/tuple.hpp> // tie
    using namespace std;
    
    #include <osg/ref_ptr>
    #include <osg/Array>
    #include <osg/Geometry>
    #include <osg/Geode>
    #include <osg/Group>
    #include <osg/LineWidth>
    using namespace osg;
    
    #include <osgUtil/Tessellator>
    #include <osgViewer/Viewer>
    using namespace osgViewer;
    
    /*
     * Just FYI: A Polyline looks like this:
     *
     *  typedef std::vector<Point> Polyline;
     *
     * And a Point basically is a simple struct:
     *
     *  struct Point {
     *      double x;
     *      double y;
     *  };
     */
    
    inline osg::Vec3d toVec3d(const straph::Point& p, double elevation=0.0)
    {
        return osg::Vec3d(p.x, p.y, elevation);
    }
    
    Geometry* createStreet(const straph::Polyline& path)
    {
        ref_ptr<Vec3dArray> array (new Vec3dArray(path.size()));
        for (unsigned i = 0; i < path.size(); ++i) {
            (*array)[i] = toVec3d(path[i]);
        }
        Geometry* geom = new Geometry;
        geom->setVertexArray(array.get());
        geom->addPrimitiveSet(new osg::DrawArrays(GL_LINE_STRIP, 0, array->size()));
        return geom;
    }
    
    Geode* load_streets()
    {
        unique_ptr<Straph> graph = read_shapefile("mexico/roads", 6);
    
        Geode* root = new Geode();
        boost::graph_traits<straph::Straph>::edge_iterator ei, ee;
        for (boost::tie(ei, ee) = edges(*graph); ei != ee; ++ei) {
            const straph::Segment& s = (*graph)[*ei];
            root->addDrawable(createStreet(s.polyline));
        }
        return root;
    }
    
    Geode* createPointer(double width, const Color& body_color, const Color& border_color)
    {
        float f0 = 0.0f;
        float f3 = 3.0f;
        float f1 = 1.0f * width;
        float f2 = 2.0f * width;
    
        // Create vertex array
        ref_ptr<Vec3Array> vertices (new Vec3Array(4));
        (*vertices)[0].set(  f0   ,  f0    , f0 );
        (*vertices)[1].set( -f1/f3, -f1/f3 , f0 );
        (*vertices)[2].set(  f0   ,  f2/f3 , f0 );
        (*vertices)[3].set(  f1/f3, -f1/f3 , f0 );
    
        // Build the geometry object
        ref_ptr<Geometry> polygon (new Geometry);
        polygon->setVertexArray( vertices.get() );
        polygon->addPrimitiveSet( new DrawArrays(GL_POLYGON, 0, 4) );
    
        // Set the colors
        ref_ptr<Vec4Array> body_colors (new Vec4Array(1));
        (*body_colors)[0] = body_color.get();
        polygon->setColorArray( body_colors.get() );
        polygon->setColorBinding( Geometry::BIND_OVERALL );
    
        // Start the tesselation work
        osgUtil::Tessellator tess;
        tess.setTessellationType( osgUtil::Tessellator::TESS_TYPE_GEOMETRY );
        tess.setWindingType( osgUtil::Tessellator::TESS_WINDING_ODD );
        tess.retessellatePolygons( *polygon );
    
        // Create the border-lines
        ref_ptr<Geometry> border (new Geometry);
        border->setVertexArray( vertices.get() );
        border->addPrimitiveSet(new DrawArrays(GL_LINE_LOOP, 0, 4));
        border->getOrCreateStateSet()->setAttribute(new LineWidth(2.0f));
    
        ref_ptr<Vec4Array> border_colors (new Vec4Array(1));
        (*border_colors)[0] = border_color.get();
        border->setColorArray( border_colors.get() );
        border->setColorBinding( Geometry::BIND_OVERALL );
    
        // Create Geode object
        ref_ptr<Geode> geode (new Geode);
        geode->addDrawable( polygon.get() );
        geode->addDrawable( border.get() );
    
        return geode.release();
    }
    
    int main(int, char**)
    {
        Group* root = new Group();
    
        Geode* str = load_streets();
        root->addChild(str);
    
        Geode* p = createPointer(6.0, TangoColor::Scarlet3, TangoColor::Black);
        root->addChild(p);
    
        Viewer viewer;
        viewer.setSceneData(root);
        viewer.getCamera()->setClearColor(Color(TangoColor::White).get());
        viewer.run();
    }
    

1 个答案:

答案 0 :(得分:1)

在函数createStreet中,我使用Vec3dArray作为顶点数组,而在createPointer函数中,我使用Vec3Array。在库中我猜它期望所有节点 由浮点数组成,但不是两者都有。更改这两个函数可以解决问题:

inline osg::Vec3 toVec3(const straph::Point& p, float elevation=0.0)
{
    return osg::Vec3(float(p.x), float(p.y), elevation);
}

Geometry* createStreet(const straph::Polyline& path)
{
    ref_ptr<Vec3Array> array (new Vec3Array(path.size()));
    for (unsigned i = 0; i < path.size(); ++i) {
        (*array)[i] = toVec3(path[i]);
    }
    Geometry* geom = new Geometry;
    geom->setVertexArray(array.get());
    geom->addPrimitiveSet(new osg::DrawArrays(GL_LINE_STRIP, 0, array->size()));
    return geom;
}

这是Robert Osfield的评论:

  

我只能提供猜测,那就是英特尔OpenGL无法正确处理双顶点数据,因此您遇到了驱动程序错误。

     

通常,OpenGL硬件基于浮点数学,因此驱动程序通常会将传递给它的任何双数据转换为浮点数,然后再将其传递给GPU。即使驱动程序正确执行此操作,此转换过程也会降低性能,因此最好将osg :: Geometry顶点/ texcoord / normal等数据保存在Floc3Array等浮点数组中。

     

您可以通过在转换为浮动之前将数据转换为本地原点来保持精确度,然后将MatrixTransform放置在数据上方以将其置于正确的3D位置。默认情况下,OSG对所有内部矩阵使用double,当它在剔除遍历期间累积modelvew矩阵时,在将最终模型视图矩阵传递给OpenGL之前,将尽可能长时间地保持双精度。使用这种技术,OSG可以处理整个地球数据,而不会出现任何抖动/精度问题。