Skip to content

Instantly share code, notes, and snippets.

@jasonbeverage
Created January 12, 2018 19:15
Show Gist options
  • Save jasonbeverage/7d3ec07b22597cc11d363fe0d8bf5b7b to your computer and use it in GitHub Desktop.
Save jasonbeverage/7d3ec07b22597cc11d363fe0d8bf5b7b to your computer and use it in GitHub Desktop.
Playing with data oriented design ideas in OSG.
#include <osgDB/ReadFile>
#include <osgUtil/Optimizer>
#include <osg/CoordinateSystemNode>
#include <osg/Point>
#include <osg/Switch>
#include <osg/Types>
#include <osgText/Text>
#include <osgViewer/Viewer>
#include <osgUtil/SceneView>
#include <osgViewer/Renderer>
#include <osgViewer/ViewerEventHandlers>
#include <osgGA/TrackballManipulator>
#include <osgGA/FlightManipulator>
#include <osgGA/DriveManipulator>
#include <osgGA/KeySwitchMatrixManipulator>
#include <osgGA/StateSetManipulator>
#include <osgGA/AnimationPathManipulator>
#include <osgGA/TerrainManipulator>
#include <osgGA/SphericalManipulator>
#include <osgGA/Device>
#include <iostream>
osg::BoundingBox bb(-100.0, -100.0, -100.0, 100.0, 100.0, 100.0);
struct StaticBoundCallback : public osg::Drawable::ComputeBoundingBoxCallback
{
StaticBoundCallback(const osg::BoundingBox& bounds):
_bounds(bounds)
{
}
virtual osg::BoundingBox computeBound(const osg::Drawable&) const {
return _bounds;
}
osg::BoundingBox _bounds;
};
osg::Geometry* createOutputGeometry()
{
osg::Geometry* geometry = new osg::Geometry;
geometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
geometry->getOrCreateStateSet()->setAttributeAndModes(new osg::Point(2.0), osg::StateAttribute::ON);
geometry->setUseDisplayList(false);
geometry->setUseVertexBufferObjects(true);
geometry->setComputeBoundingBoxCallback(new StaticBoundCallback(bb));
osg::Vec3Array* verts = new osg::Vec3Array;
geometry->setVertexArray(verts);
osg::Vec4Array* colors = new osg::Vec4Array;
geometry->setColorArray(colors, osg::Array::BIND_PER_VERTEX);
geometry->addPrimitiveSet(new osg::DrawArrays(GL_POINTS, 0, 0));
return geometry;
}
struct Point
{
osg::Vec3 position;
osg::Vec3 velocity;
osg::Vec4 color;
};
std::vector< Point > points;
#define RAND() (float)rand() / (float)RAND_MAX
osg::Vec4
randomColor()
{
float r = RAND();
float g = RAND();
float b = RAND();
return osg::Vec4(r, g, b, 1.0f);
}
osg::Vec3
randomPosition(const osg::BoundingBox& bb)
{
float x = bb.xMin() + RAND() * (bb.xMax() - bb.xMin());
float y = bb.yMin() + RAND() * (bb.yMax() - bb.yMin());
float z = bb.xMin() + RAND() * (bb.zMax() - bb.zMin());
return osg::Vec3(x, y, z);
}
void addPoint(const Point& point)
{
points.push_back(point);
}
void addRandomPoint()
{
Point p;
p.position = randomPosition(bb);
p.color = randomColor();
osg::Vec3 velocity = p.position;
velocity.normalize();
// Speed
velocity *= RAND() * 60.0;
p.velocity = velocity;
addPoint(p);
}
void update(std::vector< Point > &points, double dt)
{
osg::Timer_t startTime = osg::Timer::instance()->tick();
for (unsigned int i = 0; i < points.size(); i++)
{
points[i].position = points[i].position + points[i].velocity * dt;
}
osg::Timer_t stopTime = osg::Timer::instance()->tick();
//OSG_NOTICE << "Updated " << points.size() << " points in " << osg::Timer::instance()->delta_m(startTime, stopTime) << " ms" << std::endl;
}
void cull(const std::vector< Point > &points, const osg::Polytope& frustum, osg::Geometry* output)
{
osg::Timer_t startTime = osg::Timer::instance()->tick();
osg::Vec3Array* verts = static_cast<osg::Vec3Array*>(output->getVertexArray());
osg::Vec4Array* colors = static_cast<osg::Vec4Array*>(output->getColorArray());
if (verts->size() < points.size())
{
verts->resize(points.size());
}
if (colors->size() < points.size())
{
colors->resize(points.size());
}
unsigned int outputIndex = 0;
for (unsigned int i = 0; i < points.size(); i++)
{
if (frustum.contains(points[i].position))
{
(*verts)[outputIndex] = points[i].position;
(*colors)[outputIndex] = points[i].color;
outputIndex++;
}
}
verts->dirty();
colors->dirty();
osg::DrawArrays* drawArrays = static_cast<osg::DrawArrays*>(output->getPrimitiveSet(0));
drawArrays->setCount(outputIndex);
osg::Timer_t stopTime = osg::Timer::instance()->tick();
//OSG_NOTICE << "Culled " << points.size() << " points in " << osg::Timer::instance()->delta_m(startTime, stopTime) << " ms" << std::endl;
}
int main(int argc, char** argv)
{
//px::Scheduler schd;
//schd.init();
// use an ArgumentParser object to manage the program arguments.
osg::ArgumentParser arguments(&argc, argv);
osgViewer::Viewer viewer(arguments);
// add the state manipulator
viewer.addEventHandler(new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()));
// add the thread model handler
viewer.addEventHandler(new osgViewer::ThreadingHandler);
// add the window size toggle handler
viewer.addEventHandler(new osgViewer::WindowSizeHandler);
// add the stats handler
viewer.addEventHandler(new osgViewer::StatsHandler);
// add the help handler
viewer.addEventHandler(new osgViewer::HelpHandler(arguments.getApplicationUsage()));
// add the record camera path handler
viewer.addEventHandler(new osgViewer::RecordCameraPathHandler);
// add the LOD Scale handler
viewer.addEventHandler(new osgViewer::LODScaleHandler);
// add the screen capture handler
viewer.addEventHandler(new osgViewer::ScreenCaptureHandler);
viewer.setCameraManipulator(new osgGA::TrackballManipulator());
unsigned int numPoints = 10000;
for (unsigned int i = 0; i < numPoints; i++)
{
addRandomPoint();
}
osg::Geometry* geometry = createOutputGeometry();
viewer.setSceneData(geometry);
viewer.realize();
double time = 0.0;
while (!viewer.done())
{
if (viewer.getFrameStamp()->getFrameNumber() % 100 == 0)
{
// Add more points once in awhile.
for (unsigned int i = 0; i < 10000; i++)
{
addRandomPoint();
}
}
osg::Polytope frustum;
frustum.setToUnitFrustum();
frustum.transformProvidingInverse(viewer.getCamera()->getProjectionMatrix());
frustum.transformProvidingInverse(viewer.getCamera()->getViewMatrix());
double dt = viewer.getFrameStamp()->getSimulationTime() - time;
// Single threaded update
update(points, dt);
cull(points, frustum, geometry);
time = viewer.getFrameStamp()->getSimulationTime();
viewer.frame();
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment