2014-08-29 41 views
1

我想要将几个对象合并成一个场景图。从Geode有两套Geode的翘曲场景

  1. Street继承并取得了GL_LINE_STRIP的Geometry孩子绘制。

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

当我添加一堆街道到Group,它看起来很好。当我只将指针添加到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

在功能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; 
} 

这里由罗伯特Osfield评论:

我只能提供一个猜测,这将是英特尔的OpenGL不处理双顶点数据正确,所以你正在绊倒一个驱动程序错误。

一般而言,OpenGL硬件基于浮点数学运算,因此驱动程序通常会将所有传递给GPU的双精度数据转换为浮点数,然后再传递给GPU。即使驱动程序正确地执行此操作,该转换过程也会降低性能,因此最好将osg :: Geometry顶点/ texcoord/normal等数据全部保存在浮点数组(如Vec3Array)中。

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