I'm a newbie on OpenSceneGraph and 3D development.
I have a dxf file that contains a bunch of 3DPOLYLINES (with different colors). So far I have been able to read and display them on a viewer, but I haven been able to change the color of the rendered lines. I believe that I'm not understanding properly the graph relationships.
I'm modifying this example and using the "Quick Start Guide" as reference.
A code snippet of what I have:
osg::ref_ptr<osg::Geometry> geom = new osg::Geometry;
osg::ref_ptr<osg::Vec4Array> c = new osg::Vec4Array;
geom->setColorArray(c.get());
geom->setColorBinding(osg::Geometry::BIND_OVERALL);
c->push_back(osg::Vec4(1.f, 0.f, 0.f, 1.f));
osg::ref_ptr<osg::Vec3Array> n = new osg::Vec3Array;
geom->setNormalArray(n.get());
geom->setNormalBinding(osg::Geometry::BIND_OVERALL);
n->push_back(osg::Vec3(0.f, -1.f, 0.f));
osg::Node* lines = osgDB::readNodeFile("lines.dxf");
osg::Geode* geode = new osg::Geode;
geode->addChild(lines);
geode->addDrawable(geom.get());
std::cout << "Num Drawables in geode: " << geode->getNumDrawables() << std::endl;
osg::Camera* camera = new osg::Camera;
camera->setViewport(0, 0, this->width(), this->height());
camera->setClearColor(osg::Vec4(0.9f, 0.9f, 1.f, 1.f));
float aspectRatio = static_cast<float>(this->width()) / static_cast<float>(this->height());
camera->setProjectionMatrixAsPerspective(30.f, aspectRatio, 1.f, 1000.f);
camera->setGraphicsContext(_mGraphicsWindow);
_mViewer->setCamera(camera);
_mViewer->setSceneData(geode);
osgGA::TrackballManipulator* manipulator = new osgGA::TrackballManipulator;
//osgGA::NodeTrackerManipulator* manipulator = new osgGA::NodeTrackerManipulator;
manipulator->setAllowThrow(false);
this->setMouseTracking(true);
_mViewer->setCameraManipulator(manipulator);
_mViewer->setThreadingModel(osgViewer::Viewer::SingleThreaded);
_mViewer->realize();
I got help to my problem from the OSG forum, credits to Chris Hanson to point me in to the right direction and Gordon Tomlison's OSG Samples for the actual solution.
The code of the visitor (header):
#pragma once
#include <osg/array>
#include <osg/geode>
#include <osg/Geometry>
#include <osg/NodeVisitor>
#include <osg/Vec4>
class ColorVisitor : public osg::NodeVisitor
{
public:
ColorVisitor();
ColorVisitor(const osg::Vec4 &color);
virtual ~ColorVisitor();
virtual void apply(osg::Node &node);
virtual void apply(osg::Geode &geode);
virtual void setColor(const float r, const float g, const float b, const float a = 1.0f);
virtual void setColor(const osg::Vec4 &color);
private:
osg::Vec4 m_color;
osg::ref_ptr< osg::Vec4Array > m_colorArrays;
};
The implementation of the visitor class:
#include "ColorVisitor.h"
ColorVisitor::ColorVisitor(): osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
{
m_color.set(1.0, 1.0, 1.0, 1.0);
m_colorArrays = new osg::Vec4Array;
m_colorArrays->push_back(m_color);
};
ColorVisitor::ColorVisitor(const osg::Vec4 &color): osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
{
m_color = color;
m_colorArrays = new osg::Vec4Array;
m_colorArrays->push_back(m_color);
};
ColorVisitor::~ColorVisitor()
{
};
void ColorVisitor::apply(osg::Node &node) {
// --------------------------------------------
//
// Handle traversal of osg::Node node types
//
// --------------------------------------------
traverse(node);
};
void ColorVisitor::apply(osg::Geode &geode) {
// ------------------------------------------------
//
// Handle traversal of osg::Geode node types
//
// ------------------------------------------------
osg::StateSet *state = NULL;
unsigned int vertNum = 0;
//
// We need to iterate through all the drawables check if
// the contain any geometry that we will need to process
//
unsigned int numGeoms = geode.getNumDrawables();
for (unsigned int geodeIdx = 0; geodeIdx < numGeoms; geodeIdx++)
{
//
// Use 'asGeometry' as its supposed to be faster than a dynamic_cast
// every little saving counts
//
osg::Geometry *curGeom = geode.getDrawable(geodeIdx)->asGeometry();
//
// Only process if the drawable is geometry
//
if (curGeom)
{
osg::Vec4Array *colorArrays = dynamic_cast<osg::Vec4Array *>(curGeom->getColorArray());
if (colorArrays) {
for (unsigned int i = 0; i < colorArrays->size(); i++)
{
osg::Vec4 *color = &colorArrays->operator [](i);
//
// could also use *color = m_color
//
color->set(m_color._v[0], m_color._v[1], m_color._v[2], m_color._v[3]);
}
}
else
{
curGeom->setColorArray(m_colorArrays.get());
curGeom->setColorBinding(osg::Geometry::BIND_OVERALL);
}
}
}
};
void ColorVisitor::setColor(const float r, const float g, const float b, const float a)
{
// -------------------------------------------------------------------
//
// Set the color to change apply to the nodes geometry
//
// -------------------------------------------------------------------
osg::Vec4 *c = &m_colorArrays->operator [](0);
m_color.set(r, g, b, a);
*c = m_color;
};
void ColorVisitor::setColor(const osg::Vec4 &color) {
// -------------------------------------------------------------------
//
// Set the color to change apply to the nodes geometry
//
// -------------------------------------------------------------------
osg::Vec4 *c = &m_colorArrays->operator [](0);
m_color = color;
*c = m_color;
};
And my code simplified and updated for the solution:
osg::Node* lines = osgDB::readNodeFile("lines.dxf");
osg::Geode* geode = new osg::Geode;
ColorVisitor newColor;
newColor.setColor( 1.0f, 0.0f, 0.0f );
topography->accept(newColor);
geode->addChild(lines);
_mViewer->setSceneData(geode);
_mViewer->realize();