From Pawel Ksiezopolski, Added example of using osg::TextureBuffer + GLSL to render forest.

This commit is contained in:
Robert Osfield 2013-05-23 15:55:22 +00:00
parent 2a32bcaca6
commit 5de095cb1d

View File

@ -31,6 +31,8 @@
#include <osg/StateSet> #include <osg/StateSet>
#include <osg/Switch> #include <osg/Switch>
#include <osg/Texture2D> #include <osg/Texture2D>
#include <osg/TextureBuffer>
#include <osg/Image>
#include <osg/TexEnv> #include <osg/TexEnv>
#include <osg/VertexProgram> #include <osg/VertexProgram>
#include <osg/FragmentProgram> #include <osg/FragmentProgram>
@ -141,11 +143,14 @@ public:
osg::Node* createShaderGraph(Cell* cell,osg::StateSet* stateset); osg::Node* createShaderGraph(Cell* cell,osg::StateSet* stateset);
osg::Node* createGeometryShaderGraph(Cell* cell, osg::StateSet* stateset); osg::Node* createGeometryShaderGraph(Cell* cell, osg::StateSet* stateset);
osg::Node* createTextureBufferGraph(Cell* cell, osg::Geometry* templateGeometry);
void CollectTreePositions(Cell* cell, std::vector< osg::Vec3 >& positions); void CollectTreePositions(Cell* cell, std::vector< osg::Vec3 >& positions);
osg::Node* createHUDWithText(const std::string& text); osg::Node* createHUDWithText(const std::string& text);
osg::Node* createScene(unsigned int numTreesToCreates); osg::Node* createScene(unsigned int numTreesToCreates, unsigned int maxNumTreesPerCell);
void advanceToNextTechnique(int delta=1) void advanceToNextTechnique(int delta=1)
{ {
@ -1005,6 +1010,59 @@ osg::Node* ForestTechniqueManager::createGeometryShaderGraph(Cell* cell, osg::St
else return geode; else return geode;
} }
osg::Node* ForestTechniqueManager::createTextureBufferGraph(Cell* cell, osg::Geometry* templateGeometry)
{
bool needGroup = !(cell->_cells.empty());
bool needTrees = !(cell->_trees.empty());
osg::Geode* geode = 0;
osg::Group* group = 0;
if (needTrees)
{
osg::Geometry* geometry = (osg::Geometry*)templateGeometry->clone( osg::CopyOp::DEEP_COPY_PRIMITIVES );
osg::DrawArrays* primSet = dynamic_cast<osg::DrawArrays*>( geometry->getPrimitiveSet(0) );
primSet->setNumInstances( cell->_trees.size() );
geode = new osg::Geode;
geode->addDrawable(geometry);
osg::ref_ptr<osg::Image> treeParamsImage = new osg::Image;
treeParamsImage->allocateImage( 3*cell->_trees.size(), 1, 1, GL_RGBA, GL_FLOAT );
unsigned int i=0;
for(TreeList::iterator itr=cell->_trees.begin();
itr!=cell->_trees.end();
++itr,++i)
{
osg::Vec4f* ptr = (osg::Vec4f*)treeParamsImage->data(3*i);
Tree& tree = **itr;
ptr[0] = osg::Vec4f(tree._position.x(),tree._position.y(),tree._position.z(),1.0);
ptr[1] = osg::Vec4f((float)tree._color.r()/255.0f,(float)tree._color.g()/255.0f, (float)tree._color.b()/255.0f, 1.0);
ptr[2] = osg::Vec4f(tree._width, tree._height, 1.0, 1.0);
}
osg::ref_ptr<osg::TextureBuffer> tbo = new osg::TextureBuffer;
tbo->setImage( treeParamsImage.get() );
tbo->setInternalFormat(GL_RGBA32F);
geometry->getOrCreateStateSet()->setTextureAttribute(1, tbo.get());
geometry->setInitialBound( cell->_bb );
}
if (needGroup)
{
group = new osg::Group;
for(Cell::CellList::iterator itr=cell->_cells.begin();
itr!=cell->_cells.end();
++itr)
{
group->addChild(createTextureBufferGraph(itr->get(),templateGeometry));
}
if (geode) group->addChild(geode);
}
if (group) return group;
else return geode;
}
osg::Node* ForestTechniqueManager::createShaderGraph(Cell* cell,osg::StateSet* stateset) osg::Node* ForestTechniqueManager::createShaderGraph(Cell* cell,osg::StateSet* stateset)
@ -1103,7 +1161,7 @@ osg::Node* ForestTechniqueManager::createHUDWithText(const std::string& str)
return projection; return projection;
} }
osg::Node* ForestTechniqueManager::createScene(unsigned int numTreesToCreates) osg::Node* ForestTechniqueManager::createScene(unsigned int numTreesToCreates, unsigned int maxNumTreesPerCell)
{ {
osg::Vec3 origin(0.0f,0.0f,0.0f); osg::Vec3 origin(0.0f,0.0f,0.0f);
osg::Vec3 size(1000.0f,1000.0f,200.0f); osg::Vec3 size(1000.0f,1000.0f,200.0f);
@ -1120,7 +1178,7 @@ osg::Node* ForestTechniqueManager::createScene(unsigned int numTreesToCreates)
std::cout<<"Creating cell subdivision..."; std::cout<<"Creating cell subdivision...";
osg::ref_ptr<Cell> cell = new Cell; osg::ref_ptr<Cell> cell = new Cell;
cell->addTrees(trees); cell->addTrees(trees);
cell->divide(); cell->divide(maxNumTreesPerCell);
std::cout<<"done."<<std::endl; std::cout<<"done."<<std::endl;
@ -1153,7 +1211,7 @@ osg::Node* ForestTechniqueManager::createScene(unsigned int numTreesToCreates)
std::cout<<"Creating osg::Billboard based forest..."; std::cout<<"Creating osg::Billboard based forest...";
osg::Group* group = new osg::Group; osg::Group* group = new osg::Group;
group->addChild(createBillboardGraph(cell.get(),dstate)); group->addChild(createBillboardGraph(cell.get(),dstate));
group->addChild(createHUDWithText("Using osg::Billboard's to create a forest\n\nPress left cursor key to select osg::Vertex/Geometry/FragmentProgram shader based forest\nPress right cursor key to select double quad based forest")); group->addChild(createHUDWithText("Using osg::Billboard's to create a forest\n\nPress left cursor key to select geometry instancing with Texture Buffer Object\nPress right cursor key to select double quad based forest"));
_techniqueSwitch->addChild(group); _techniqueSwitch->addChild(group);
std::cout<<"done."<<std::endl; std::cout<<"done."<<std::endl;
} }
@ -1306,11 +1364,80 @@ osg::Node* ForestTechniqueManager::createScene(unsigned int numTreesToCreates)
osg::Group* group = new osg::Group; osg::Group* group = new osg::Group;
group->addChild(createGeometryShaderGraph(cell.get(), stateset)); group->addChild(createGeometryShaderGraph(cell.get(), stateset));
group->addChild(createHUDWithText("Using osg::Vertex/Geometry/FragmentProgram to create a forest\n\nPress left cursor key to select OpenGL Shader based forest\nPress right cursor key to select osg::Billboard based forest")); group->addChild(createHUDWithText("Using osg::Vertex/Geometry/FragmentProgram to create a forest\n\nPress left cursor key to select OpenGL Shader based forest\nPress right cursor key to select geometry instancing with Texture Buffer Object"));
_techniqueSwitch->addChild(group); _techniqueSwitch->addChild(group);
std::cout<<"done."<<std::endl; std::cout<<"done."<<std::endl;
} }
{
std::cout<<"Creating forest using geometry instancing and texture buffer objects ...";
osg::StateSet* stateset = new osg::StateSet(*dstate, osg::CopyOp::DEEP_COPY_ALL);
{
osg::Program* program = new osg::Program;
stateset->setAttribute(program);
char vertexShaderSource[] =
"#version 420 compatibility\n"
"uniform samplerBuffer dataBuffer;\n"
"layout(location = 0) in vec3 VertexPosition;\n"
"layout(location = 8) in vec3 VertexTexCoord;\n"
"out vec2 TexCoord;\n"
"out vec4 Color;\n"
"void main()\n"
"{\n"
" int instanceAddress = gl_InstanceID * 3;\n"
" vec3 position = texelFetch(dataBuffer, instanceAddress).xyz;\n"
" Color = texelFetch(dataBuffer, instanceAddress + 1);\n"
" vec2 size = texelFetch(dataBuffer, instanceAddress + 2).xy;\n"
" mat4 mvpMatrix = gl_ModelViewProjectionMatrix *\n"
" mat4( size.x, 0.0, 0.0, 0.0,\n"
" 0.0, size.x, 0.0, 0.0,\n"
" 0.0, 0.0, size.y, 0.0,\n"
" position.x, position.y, position.z, 1.0);\n"
" gl_Position = mvpMatrix * vec4(VertexPosition,1.0) ;\n"
" TexCoord = VertexTexCoord.xy;\n"
"}\n";
char fragmentShaderSource[] =
"#version 420 core\n"
"uniform sampler2D baseTexture; \n"
"in vec2 TexCoord;\n"
"in vec4 Color;\n"
"layout(location = 0, index = 0) out vec4 FragData0;\n"
"void main(void) \n"
"{\n"
" FragData0 = Color*texture(baseTexture, TexCoord);\n"
"}\n";
osg::Shader* vertex_shader = new osg::Shader(osg::Shader::VERTEX, vertexShaderSource);
program->addShader(vertex_shader);
osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource);
program->addShader(fragment_shader);
osg::Uniform* baseTextureSampler = new osg::Uniform("baseTexture",0);
stateset->addUniform(baseTextureSampler);
osg::Uniform* dataBufferSampler = new osg::Uniform("dataBuffer",1);
stateset->addUniform(dataBufferSampler);
}
osg::ref_ptr<osg::Geometry> templateGeometry = createOrthogonalQuadsNoColor(osg::Vec3(0.0f,0.0f,0.0f),1.0f,1.0f);
templateGeometry->setUseVertexBufferObjects(true);
templateGeometry->setUseDisplayList(false);
osg::Node* textureBufferGraph = createTextureBufferGraph(cell.get(), templateGeometry.get());
textureBufferGraph->setStateSet( stateset );
osg::Group* group = new osg::Group;
group->addChild(textureBufferGraph);
group->addChild(createHUDWithText("Using geometry instancing to create a forest\n\nPress left cursor key to select osg::Vertex/Geometry/FragmentProgram based forest\nPress right cursor key to select osg::Billboard based forest"));
_techniqueSwitch->addChild(group);
std::cout<<"done."<<std::endl;
}
_currentTechnique = 0; _currentTechnique = 0;
_techniqueSwitch->setSingleChildOn(_currentTechnique); _techniqueSwitch->setSingleChildOn(_currentTechnique);
@ -1333,11 +1460,15 @@ int main( int argc, char **argv )
// construct the viewer. // construct the viewer.
osgViewer::Viewer viewer(arguments); osgViewer::Viewer viewer(arguments);
float numTreesToCreates = 10000; unsigned int numTreesToCreate = 10000;
arguments.read("--trees",numTreesToCreates); arguments.read("--trees",numTreesToCreate);
unsigned int maxNumTreesPerCell = sqrtf(static_cast<float>(numTreesToCreate));
arguments.read("--trees-per-cell",maxNumTreesPerCell);
osg::ref_ptr<ForestTechniqueManager> ttm = new ForestTechniqueManager; osg::ref_ptr<ForestTechniqueManager> ttm = new ForestTechniqueManager;
// add the stats handler // add the stats handler
viewer.addEventHandler(new osgViewer::StatsHandler); viewer.addEventHandler(new osgViewer::StatsHandler);
@ -1345,7 +1476,7 @@ int main( int argc, char **argv )
viewer.addEventHandler(new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet())); viewer.addEventHandler(new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()));
// add model to viewer. // add model to viewer.
viewer.setSceneData( ttm->createScene((unsigned int)numTreesToCreates) ); viewer.setSceneData( ttm->createScene(numTreesToCreate, maxNumTreesPerCell) );
return viewer.run(); return viewer.run();