Skip to content

Instantly share code, notes, and snippets.

@fulezi
Created December 1, 2017 09:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fulezi/95a9ac319fd1cbeca1b18a4cde3986dc to your computer and use it in GitHub Desktop.
Save fulezi/95a9ac319fd1cbeca1b18a4cde3986dc to your computer and use it in GitHub Desktop.
OpenSceneGraph - Display model normals
#include "CollectNormalsVisitor.hpp"
#include <cassert>
#include <osg/Geode>
#include <osg/Geometry>
namespace ose {
CollectNormalsVisitor::CollectNormalsVisitor(const float magnitude)
: NodeVisitor(osg::NodeVisitor::TraversalMode::TRAVERSE_ACTIVE_CHILDREN)
, magnitude(magnitude)
{
}
void CollectNormalsVisitor::apply(osg::Geode& geode)
{
for (unsigned int it = 0; it < geode.getNumDrawables(); ++it) {
const osg::Drawable* childDrawable = geode.getDrawable(it);
assert(childDrawable);
const osg::Geometry* geometry = childDrawable->asGeometry();
/* We only support geometry */
if (geometry) {
const osg::Vec3Array* normals =
dynamic_cast<const osg::Vec3Array*>(geometry->getNormalArray());
assert(normals);
const osg::Vec3Array* vertices =
dynamic_cast<const osg::Vec3Array*>(geometry->getVertexArray());
assert(vertices);
assert(normals->getBinding() == osg::Array::Binding::BIND_PER_VERTEX &&
"// TODO: Support other binding mods");
osg::Matrix world = osg::computeWorldToLocal(this->getNodePath());
for (unsigned int it = 0; it < vertices->size(); ++it) {
const osg::Vec3& lineBegin = world * (*vertices)[it];
const osg::Vec3& lineEnd = lineBegin + (*normals)[it] * magnitude;
normalList.push_back(lineBegin);
normalList.push_back(lineEnd);
}
} else {
osg::notify() << "Skipping non-geometry Drawable:"
<< childDrawable->getName() << "\n";
}
}
traverse(geode);
}
osg::ref_ptr<osg::Geode> CollectNormalsVisitor::toNormalsGeomtery(
osg::Vec4 color)
{
osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
vertices->insert(vertices->begin(), normalList.begin(), normalList.end());
osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array;
colors->push_back(color);
osg::ref_ptr<osg::Geometry> norms = new osg::Geometry;
norms->setVertexArray(vertices);
norms->setColorArray(colors);
norms->setColorBinding(osg::Geometry::BIND_OVERALL);
norms->addPrimitiveSet(new osg::DrawArrays(GL_LINES, 0, vertices->size()));
osg::ref_ptr<osg::Geode> leaf = new osg::Geode;
// Make sure to deactivate the lighting
leaf->getOrCreateStateSet()->setMode(
GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED);
leaf->addDrawable(norms);
return leaf;
}
} // ose
#include <osg/NodeVisitor>
namespace ose {
/**
* Compute a representation of normals from children geometries.
*
* Normals are bound to vertices.
* The length of each normal is controlled with the magniture parameter.
*/
struct CollectNormalsVisitor : public osg::NodeVisitor
{
/** Vector of normal lines: [normal1-begin, normal1-end, ...] */
std::vector<osg::Vec3> normalList;
float magnitude;
CollectNormalsVisitor(const float magnitude = 2.0f);
void apply(osg::Geode& geode) override;
osg::ref_ptr<osg::Geode> toNormalsGeomtery(
osg::Vec4 color = osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f));
};
} // ose
#include "CollectNormalsVisitor.hpp"
int
main(int argc, char** argv)
{
// Load your model
osg::ref_ptr<osg::Node> model = osgDB::readNodeFile(fileToOpen);
// Collect all the geometries normals from parent to children
ose::CollectNormalsVisitor c;
model->accept(c);
// Generate the new geometry (a list of gl_lines) and add them to the root
osg::ref_ptr<osg::MatrixTransform> root = new osg::MatrixTransform;
root->addChild(c.toNormalsGeomtery(osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f)));
/* Add the root to the viewer ... */
return 0;
}
@fulezi
Copy link
Author

fulezi commented Dec 1, 2017

A quick way to get and display normals with OSG.
Currently only 'standard' geometries with BIND_PER_VERTEX are supported.
But you get the concept. It's easy to go beyond :)

truck-normals

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment