Created
January 12, 2018 19:15
-
-
Save jasonbeverage/7d3ec07b22597cc11d363fe0d8bf5b7b to your computer and use it in GitHub Desktop.
Playing with data oriented design ideas in OSG.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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