Advertisement
Guest User

Untitled

a guest
Apr 15th, 2016
169
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 9.17 KB | None | 0 0
  1.  
  2. #include "instancedmapgamestate.hpp"
  3. #include "findfilecallbackdsmap.hpp"
  4.  
  5. #include <osgDB/ReadFile>
  6. #include <osg/MatrixTransform>
  7. #include <iostream>
  8.  
  9. namespace siege
  10. {
  11.     const std::string instanceVert =
  12.  
  13.         "uniform mat4 instanceModelMatrix[MAX_INSTANCES];\n"
  14.  
  15.         "smooth out vec2 texCoord;\n"
  16.  
  17.         "void main()\n"
  18.         "{\n"
  19.         "mat4 _instanceModelMatrix = instanceModelMatrix[gl_InstanceID];\n"
  20.         "gl_Position = gl_ModelViewProjectionMatrix * _instanceModelMatrix * gl_Vertex;\n"
  21.         "texCoord = gl_MultiTexCoord0.xy;\n"
  22.         "}\n";
  23.  
  24.     const std::string instanceFrag =
  25.  
  26.         "#version 150 compatibility\n"
  27.  
  28.         "uniform sampler2D colorTexture;\n"
  29.         "smooth in vec2 texCoord;\n"
  30.  
  31.         "void main()\n"
  32.         "{\n"
  33.         "vec4 textureColor = texture2D(colorTexture, texCoord);\n"
  34.         "gl_FragColor = vec4(textureColor.rgb, textureColor.a);\n"
  35.         "}\n";
  36.  
  37.     struct ModelInstance
  38.     {
  39.         ModelInstance() : mObjectId(-1) {}
  40.         osg::Matrix matrix;
  41.         uint32_t mObjectId;
  42.     };
  43.  
  44.     typedef std::map< osg::ref_ptr<osg::Node>, std::vector<ModelInstance> > ModelInstanceMap;
  45.  
  46.     struct ComputeInstancedBoundingBoxCallback : public osg::Drawable::ComputeBoundingBoxCallback
  47.     {
  48.         public:
  49.  
  50.             ComputeInstancedBoundingBoxCallback(osg::ref_ptr<osg::Uniform> instanceMatrices): mInstanceMatrices(instanceMatrices)
  51.             {
  52.             }
  53.  
  54.             virtual osg::BoundingBox computeBound(const osg::Drawable& drawable) const
  55.             {
  56.                 osg::BoundingBox bounds;
  57.                 const osg::Geometry* geometry = dynamic_cast<const osg::Geometry*>(&drawable);
  58.  
  59.                 if (!geometry)
  60.                     return bounds;
  61.  
  62.                 const osg::Vec3Array* vertices = dynamic_cast<const osg::Vec3Array*>(geometry->getVertexArray());
  63.  
  64.                 for (unsigned int i = 0; i < mInstanceMatrices->getNumElements(); ++i)
  65.                 {
  66.                     osg::Matrixd matrix;
  67.                     mInstanceMatrices->getElement(i, matrix);
  68.  
  69.                     for (auto it = vertices->begin(); it != vertices->end(); ++it)
  70.                     {
  71.                         bounds.expandBy(*it * matrix);
  72.                     }
  73.                 }
  74.  
  75.                 return bounds;
  76.             }
  77.  
  78.         private:
  79.             osg::ref_ptr<osg::Uniform> mInstanceMatrices;
  80.  
  81.     };
  82.  
  83.     class ConvertToDrawInstanced : public osg::NodeVisitor
  84.     {
  85.     public:
  86.  
  87.         ConvertToDrawInstanced(unsigned numInstances, const osg::BoundingBox &bbox, bool optimize) : mNumInstances(numInstances), mOptimize(optimize)
  88.         {
  89.             setTraversalMode(TRAVERSE_ALL_CHILDREN);
  90.             setNodeMaskOverride(~0);
  91.         }
  92.  
  93.         void apply(osg::Geode &geode)
  94.         {
  95.             for (unsigned d = 0; d < geode.getNumDrawables(); ++d)
  96.             {
  97.                 osg::Geometry *geom = geode.getDrawable(d)->asGeometry();
  98.                 if (geom != nullptr)
  99.                 {
  100.                     if (mOptimize)
  101.                     {
  102.                         geom->setUseDisplayList(false);
  103.                         geom->setUseVertexBufferObjects(true);
  104.                     }
  105.  
  106.                     for (unsigned int p = 0; p < geom->getNumPrimitiveSets(); ++p)
  107.                     {
  108.                         osg::PrimitiveSet *ps = geom->getPrimitiveSet(0);
  109.                         ps->setNumInstances(mNumInstances);
  110.                         mPrimitiveSets.push_back(ps);
  111.                     }
  112.                 }
  113.             }
  114.  
  115.             traverse(geode);
  116.         }
  117.  
  118.     protected:
  119.  
  120.         unsigned mNumInstances;
  121.         bool mOptimize;
  122.         std::list<osg::PrimitiveSet *> mPrimitiveSets;
  123.     };
  124.  
  125.     osg::ref_ptr<osg::Node> InstancedMapGameState::createHardwareInstancedNode(osg::Node *node, const std::vector <ModelInstance> &instances, int start, int end)
  126.     {
  127.         osg::Geode *geode = new osg::Geode(*node->asGeode(), osg::CopyOp::DEEP_COPY_ALL);
  128.  
  129.         // Enable the geometry to be instanced
  130.         ConvertToDrawInstanced cdi(end - start, osg::BoundingBox(), true);
  131.         geode->accept(cdi);
  132.  
  133.         // Create a uniform to pass to the shader
  134.         osg::ref_ptr<osg::Uniform> instanceMatrixUniform = new osg::Uniform(osg::Uniform::FLOAT_MAT4, "instanceModelMatrix");
  135.  
  136.         // Iterate over each instance to get matrix information
  137.         for (unsigned m = start, j = 0; m < end; ++m, ++j)
  138.         {
  139.             const osg::Matrix &mat = instances[m].matrix;
  140.  
  141.             // Assign matrix to the uniform
  142.             instanceMatrixUniform->setElement(j, mat);
  143.         }
  144.  
  145.         geode->getOrCreateStateSet()->addUniform(instanceMatrixUniform);
  146.  
  147.         geode->getDrawable(0)->setComputeBoundingBoxCallback(new ComputeInstancedBoundingBoxCallback(instanceMatrixUniform));
  148.  
  149.         return geode;
  150.     }
  151.  
  152.     bool InstancedMapGameState::convertGraphToUseDrawInstanced(osg::Group *parent)
  153.     {
  154.         // Store our hardware limit and actual matrix limit
  155.         int32_t hardwareLimit = app().getMaxNumUniforms();
  156.         int32_t maxInstanceMatrices = (hardwareLimit - 16) / 16;
  157.  
  158.         // Define an instance map to hold all instances of models in a map
  159.         ModelInstanceMap models;
  160.  
  161.         // Iterate over the group
  162.         for (unsigned i = 0; i < parent->getNumChildren(); ++i)
  163.         {
  164.             osg::MatrixTransform *mt = dynamic_cast<osg::MatrixTransform *> (parent->getChild(i));
  165.  
  166.             if (mt != nullptr)
  167.             {
  168.                 osg::Node *n = mt->getChild(0);
  169.  
  170.                 ModelInstance instance;
  171.                 instance.matrix = mt->getMatrix();
  172.  
  173.                 // Store the instance
  174.                 models[n].push_back(instance);
  175.             }
  176.         }
  177.  
  178.         std::cout << "There are " << models.size() << " unique models in the map" << std::endl;
  179.  
  180.         // Clear out current scene graph
  181.         parent->removeChildren(0, parent->getNumChildren());
  182.  
  183.         // Create our shader program
  184.         osg::ref_ptr<osg::Program> program = new osg::Program();
  185.  
  186.         // Add preprocessor definition to the instance vertex shader
  187.         std::stringstream preprocessor;
  188.         preprocessor << "#version 150 compatibility\n #define MAX_INSTANCES " << maxInstanceMatrices << "\n";
  189.         std::cout << preprocessor.str().c_str() << std::endl;
  190.         preprocessor << instanceVert;
  191.  
  192.         // Add our vertex and fragment shaders
  193.         program->addShader(new osg::Shader(osg::Shader::VERTEX, preprocessor.str()));
  194.         program->addShader(new osg::Shader(osg::Shader::FRAGMENT, instanceFrag));
  195.  
  196.         // Assign our shader to the parent of the scene graph
  197.         parent->getOrCreateStateSet()->setAttribute(program, osg::StateAttribute::ON);
  198.  
  199.         // Iterate over each model and attempt to create a group out of it for instancing
  200.         for (ModelInstanceMap::iterator i = models.begin(); i != models.end(); ++i)
  201.         {
  202.             osg::Node *node = i->first.get();
  203.             std::vector<ModelInstance> &instances = i->second;
  204.  
  205.             // Check to make sure our instance size can fit in one group
  206.             if (instances.size() <= maxInstanceMatrices)
  207.             {
  208.                 // Add the new geode to the scene graph
  209.                 parent->addChild(createHardwareInstancedNode(node, instances, 0, instances.size()));
  210.             }
  211.             else
  212.             {
  213.                 std::cout << "WARNING: Instance size is: " << instances.size() << " hardware limit is: " << maxInstanceMatrices << " - ATTEMPTING TO SPLIT NODES!" << std::endl;
  214.  
  215. #if 0
  216.                 unsigned int numGeodes = std::ceil((uint32_t)instances.size() / maxInstanceMatrices);
  217.                 for (uint32_t g = 0; g < numGeodes; ++g)
  218.                 {
  219.                     unsigned int start = g * maxInstanceMatrices;
  220.                     unsigned int end = std::min((unsigned int)instances.size(), (start + maxInstanceMatrices));
  221.  
  222.                     parent->addChild(createHardwareInstancedNode(node, instances, start, end));
  223.                 }
  224. #endif
  225.             }
  226.         }
  227.  
  228.         return true;
  229.     }
  230.  
  231.     InstancedMapGameState::InstancedMapGameState(Application & app) : GameState(app)
  232.     {
  233.     }
  234.  
  235.     InstancedMapGameState::~InstancedMapGameState()
  236.     {
  237.     }
  238.  
  239.     void InstancedMapGameState::onEnter()
  240.     {
  241.         const std::string regionFileName = "town_center.dsmap";
  242.  
  243.         std::cout << "InstancedMapGameState::onEnter: " << regionFileName << std::endl;
  244.  
  245.         // add a stats handler so we can see our scene graph stats
  246.         app().addEventHandler(new osgViewer::StatsHandler);
  247.  
  248.         // load the region
  249.         osg::ref_ptr<osg::Node> regionA = osgDB::readNodeFile(regionFileName, useDSMAPOption());
  250.  
  251.         std::cout << "Finished load Town Center" << std::endl;
  252.  
  253.         // Check if we support instance drawing
  254.         if (!app().supportsDrawInstanced())
  255.         {
  256.             // add the switch to the application
  257.             app().setSceneData(regionA.get());
  258.  
  259.             return;
  260.         }
  261.  
  262.         // Try to instance the map
  263.         convertGraphToUseDrawInstanced(regionA->asGroup());
  264.  
  265.         app().setSceneData(regionA.get());
  266.     }
  267. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement