Деформированная сцена с двумя наборами геодезов

У меня есть несколько объектов, которые я хочу объединить в граф сцены.

  1. Street наследуется от Geode и имеет Geometry дочерний чертеж, составленный из GL_LINE_STRIP.

  2. Pointer наследуется от PositionAttitudeTransform и содержит Geode который содержит два Geometry многоугольники.

Когда я добавляю несколько улиц к GroupЭто выглядит просто отлично. Когда я добавляю только Указатель к Group, это также выглядит хорошо. Но если у меня как-то есть они оба на сцене, то второй облажался. Смотрите две картинки.

Один вид, когда улицы первые

На рисунке выше уличная сеть соответствует желаемому, а на рисунке ниже указатель соответствует желаемому.

Один вид, когда указатель первый

Буду признателен за любую помощь! Если вам нужно увидеть код, дайте мне знать, и я обновлю свой вопрос.

Обновление 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;
}

Вот комментарий Роберта Осфилда:

Я могу только дать предположение, и это означает, что Intel OpenGL неправильно обрабатывает данные двух вершин, поэтому вы наткнулись на ошибку драйвера.

В целом, оборудование OpenGL основано на математике с плавающей запятой, поэтому драйверы обычно преобразуют любые двойные данные, которые вы передаете, в плавающие числа перед передачей их в графический процессор. Даже если драйвер делает это правильно, этот процесс преобразования замедляет производительность, поэтому лучше хранить данные osg::Geometry vertex/texcoord/normal и т. Д. В массивах с плавающей точкой, таких как Vec3Array.

Вы можете сохранить точность, переведя свои данные в локальный источник до преобразования в плавающее значение, а затем поместите MatrixTransform над вашими данными, чтобы поместить их в правильное трехмерное положение. OSG по умолчанию использует double для всех внутренних матриц, чтобы при нахождении матрицы modelww во время обхода отбраковки сохранялась как можно дольше, прежде чем передать окончательную матрицу просмотра модели в OpenGL. Используя эту технику, OSG может обрабатывать данные всей земли без каких-либо проблем с дрожанием / точностью.

Другие вопросы по тегам