Деформированная сцена с двумя наборами геодезов
У меня есть несколько объектов, которые я хочу объединить в граф сцены.
Street
наследуется отGeode
и имеетGeometry
дочерний чертеж, составленный из GL_LINE_STRIP.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 может обрабатывать данные всей земли без каких-либо проблем с дрожанием / точностью.