151 lines
5.7 KiB
C++
151 lines
5.7 KiB
C++
/* OpenSceneGraph example, osgdrawinstanced.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
*/
|
|
//
|
|
// This code is copyright (c) 2008 Skew Matrix Software LLC. You may use
|
|
// the code under the licensing terms described above.
|
|
//
|
|
|
|
#include <osgDB/ReadFile>
|
|
#include <osgViewer/Viewer>
|
|
#include <osg/Geometry>
|
|
#include <osg/Texture2D>
|
|
|
|
#include <osgDB/WriteFile>
|
|
|
|
#include <iostream>
|
|
|
|
void
|
|
createDAIGeometry( osg::Geometry& geom, int nInstances=1 )
|
|
{
|
|
const float halfDimX( .5 );
|
|
const float halfDimZ( .5 );
|
|
|
|
osg::Vec3Array* v = new osg::Vec3Array;
|
|
v->resize( 4 );
|
|
geom.setVertexArray( v );
|
|
|
|
// Geometry for a single quad.
|
|
(*v)[ 0 ] = osg::Vec3( -halfDimX, 0., -halfDimZ );
|
|
(*v)[ 1 ] = osg::Vec3( halfDimX, 0., -halfDimZ );
|
|
(*v)[ 2 ] = osg::Vec3( halfDimX, 0., halfDimZ );
|
|
(*v)[ 3 ] = osg::Vec3( -halfDimX, 0., halfDimZ );
|
|
|
|
// Use the DrawArraysInstanced PrimitiveSet and tell it to draw 1024 instances.
|
|
geom.addPrimitiveSet( new osg::DrawArrays( GL_QUADS, 0, 4, nInstances ) );
|
|
}
|
|
|
|
|
|
osg::StateSet*
|
|
createStateSet()
|
|
{
|
|
osg::ref_ptr< osg::StateSet > ss = new osg::StateSet;
|
|
|
|
// Create a vertex program that references the gl_InstanceID to
|
|
// render each instance uniquely. gl_InstanceID will be in the range
|
|
// 0 to numInstances-1 (1023 in our case).
|
|
std::string vertexSource =
|
|
"uniform sampler2D osgLogo; \n"
|
|
"uniform float osg_SimulationTime; \n"
|
|
|
|
"void main() \n"
|
|
"{ \n"
|
|
// Using the instance ID, generate "texture coords" for this instance.
|
|
"vec2 tC; \n"
|
|
"float r = float(gl_InstanceID) / 32.; \n"
|
|
"tC.s = fract( r ); tC.t = floor( r ) / 32.; \n"
|
|
// Get the color from the OSG logo.
|
|
"gl_FrontColor = texture2D( osgLogo, tC ); \n"
|
|
|
|
// Use the (scaled) tex coord to translate the position of the vertices.
|
|
"vec4 pos = vec4( tC.s * 48., 0., tC.t * 48., 1. ); \n"
|
|
|
|
// Compute a rotation angle from the instanceID and elapsed time.
|
|
"float timeOffset = gl_InstanceID / (32. * 32.); \n"
|
|
"float angle = ( osg_SimulationTime - timeOffset ) * 6.283; \n"
|
|
"float sa = sin( angle ); \n"
|
|
"float ca = cos( angle ); \n"
|
|
// New orientation, rotate around z axis.
|
|
"vec4 newX = vec4( ca, sa, 0., 0. ); \n"
|
|
"vec4 newY = vec4( sa, ca, 0., 0. ); \n"
|
|
"vec4 newZ = vec4( 0., 0., 1., 0. ); \n"
|
|
"mat4 mV = mat4( newX, newY, newZ, pos ); \n"
|
|
"gl_Position = ( gl_ModelViewProjectionMatrix * mV * gl_Vertex ); \n"
|
|
"} \n";
|
|
|
|
osg::ref_ptr< osg::Shader > vertexShader = new osg::Shader();
|
|
vertexShader->setType( osg::Shader::VERTEX );
|
|
vertexShader->setShaderSource( vertexSource );
|
|
|
|
osg::ref_ptr< osg::Program > program = new osg::Program();
|
|
program->addShader( vertexShader.get() );
|
|
|
|
ss->setAttribute( program.get(),
|
|
osg::StateAttribute::ON | osg::StateAttribute::PROTECTED );
|
|
|
|
osg::ref_ptr< osg::Image> iLogo = osgDB::readImageFile( "Images/osg128.png" );
|
|
if( !iLogo.valid() )
|
|
{
|
|
osg::notify( osg::ALWAYS ) << "Can't open image file osg128.png" << std::endl;
|
|
return( NULL );
|
|
}
|
|
osg::Texture2D* texLogo = new osg::Texture2D( iLogo.get() );
|
|
texLogo->setFilter( osg::Texture2D::MIN_FILTER, osg::Texture2D::LINEAR );
|
|
texLogo->setFilter( osg::Texture2D::MAG_FILTER, osg::Texture2D::LINEAR );
|
|
|
|
ss->setTextureAttribute( 0, texLogo );
|
|
|
|
osg::ref_ptr< osg::Uniform > texLogoUniform =
|
|
new osg::Uniform( "osgLogo", 0 );
|
|
ss->addUniform( texLogoUniform.get() );
|
|
|
|
return( ss.release() );
|
|
}
|
|
|
|
|
|
int main( int argc, char **argv )
|
|
{
|
|
osg::ArgumentParser arguments(&argc, argv);
|
|
|
|
// Make a scene graph consisting of a single Geode, containing
|
|
// a single Geometry, and a single PrimitiveSet.
|
|
osg::ref_ptr< osg::Geode > geode = new osg::Geode;
|
|
|
|
osg::ref_ptr< osg::Geometry > geom = new osg::Geometry;
|
|
// Configure the Geometry for use with EXT_draw_arrays:
|
|
// DL off and buffer objects on.
|
|
geom->setUseDisplayList( false );
|
|
geom->setUseVertexBufferObjects( true );
|
|
// OSG has no clue where out vertex shader will place the geometric data,
|
|
// so specify an initial bound to allow proper culling and near/far computation.
|
|
osg::BoundingBox bb( -1., -.1, -1., 49., 1., 49. );
|
|
geom->setInitialBound( bb );
|
|
// Add geometric data and the PrimitiveSet. Specify numInstances as 32*32 or 1024.
|
|
createDAIGeometry( *geom, 32*32 );
|
|
geode->addDrawable( geom.get() );
|
|
|
|
// Create a StateSet to render the instanced Geometry.
|
|
osg::ref_ptr< osg::StateSet > ss = createStateSet();
|
|
geode->setStateSet( ss.get() );
|
|
|
|
// osgDB::writeNodeFile(*geode, "instanced.osg");
|
|
|
|
osgViewer::Viewer viewer(arguments);
|
|
viewer.setSceneData( geode.get() );
|
|
return viewer.run();
|
|
}
|