2014-12-10 20:23:04 +08:00
//info : osgSSBO example,testing ShaderStorageBufferObjects ,Markus Hein, 2014, osg-3.2.1
//required hardware and driver must support GL >= GL 4.3 or GL ES 3.1 (GL ES not tested, would be nice if someone will test it on a small device)
//testing osg support for Shader Storage Buffer Objects
//version: "first take" from last night session..
# include <osg/StateAttributeCallback>
# include <osg/Texture2D>
# include <osg/Geometry>
# include <osg/Geode>
# include <osgDB/ReadFile>
# include <osgGA/StateSetManipulator>
# include <osgViewer/Viewer>
# include <osgViewer/ViewerEventHandlers>
# include <osg/Node>
# include <osg/PositionAttitudeTransform>
# include <osg/Geometry>
# include <osg/Notify>
# include <osg/MatrixTransform>
# include <osg/Texture2D>
# include <osg/TextureRectangle>
# include <osg/Stencil>
# include <osg/Depth>
# include <osg/Billboard>
# include <osg/Material>
# include <osg/AnimationPath>
# include <osgGA/TrackballManipulator>
# include <osgGA/FlightManipulator>
# include <osgGA/DriveManipulator>
# include <osgUtil/SmoothingVisitor>
# include <osgDB/Registry>
# include <osgDB/ReadFile>
# include <osgDB/WriteFile>
# include <osgViewer/Viewer>
# include <osgViewer/ViewerEventHandlers>
# include <osgViewer/Renderer>
# include <osg/Array>
# include <osg/BoundingSphere>
# include <osg/BufferIndexBinding>
# include <osg/BufferObject>
# include <osg/Group>
# include <osg/Math>
# include <osg/MatrixTransform>
# include <osg/Program>
# include <osg/Shader>
# include <osg/Drawable>
# include <osg/CopyOp>
# include <osg/State>
# include <osg/Matrix>
# include <osg/ShapeDrawable>
# include <osg/GL>
# include <osg/StateSet>
# include <osg/Texture2D>
# include <osg/BlendFunc>
# include <osg/TexEnv>
# include <osg/Material>
# include <osg/PointSprite>
# include <osg/Program>
# include <osg/Notify>
# include <osg/Point>
# include <osg/io_utils>
# include <osg/VertexProgram>
# include <osgText/Font>
# include <osgText/Text>
# include <osgDB/ReadFile>
# include <osgDB/WriteFile>
# include <osgDB/FileNameUtils>
# include <osgUtil/Optimizer>
# include <iostream>
# include <typeinfo>
using namespace osg ;
//todo .. #define COMPUTATION_IN_SEPARATE_THREAD
# define WORK_GROUP_SIZE 16
# define PRERENDER_ANTIALIASINGMULTISAMPLES 16
# define PRERENDER_HIGH_QUALITY_ANTIALIASING
# define PRERENDER_WIDTH 1920
# define PRERENDER_HEIGHT 1080
# define SUB_PLACEMENT_OFFSET_HORIZONTAL 0.5
# define SUB_PLACEMENT_OFFSET_VERTICAL 0.5
enum BufferOffset
{
POSITION_NOW_OFFSET ,
POSITION_OLD_OFFSET ,
POSITION_INIT_OFFSET ,
VELOCITY_NOW_OFFSET ,
VELOCITY_OLD_OFFSET ,
VELOCITY_INIT_OFFSET ,
ACCELERATION_OFFSET ,
PROPERTIES_OFFSET ,
OFFSET_END
} ;
const int __numDataValuesPerChannel = OFFSET_END ;
const int __numChannels = 4 ;
const float __particleRenderScaleMultiplier = 0.3 ;
//512x512x4x7 = 7.340.032 floats in SSBO on GPU
const int NUM_ELEMENTS_X = 512 ;
const int NUM_ELEMENTS_Y = 512 ;
float random ( float min , float max ) { return min + ( max - min ) * ( float ) rand ( ) / ( float ) RAND_MAX ; }
enum Channel
{
RED_CHANNEL ,
GREEN_CHANNEL ,
BLUE_CHANNEL ,
ALPHA_CHANNEL ,
RGB_CHANNEL ,
RGBA_CHANNEL
} ;
class ShaderStorageBufferCallback : public osg : : StateAttributeCallback
{
public :
void operator ( ) ( osg : : StateAttribute * attr , osg : : NodeVisitor * nv )
{
//if you need to process the data in your app-code , better leaving it on GPU and processing there, uploading per frame will make it slow
#if 0
osg : : ShaderStorageBufferBinding * ssbb = static_cast < osg : : ShaderStorageBufferBinding * > ( attr ) ;
osg : : ShaderStorageBufferObject * ssbo
= static_cast < osg : : ShaderStorageBufferObject * > ( ssbb - > getBufferObject ( ) ) ;
osg : : FloatArray * array = static_cast < osg : : FloatArray * > ( ssbo - > getBufferData ( 0 ) ) ;
float someValue = array - > at ( 0 ) ;
//std::cout << "someValue now: " << someValue << std::endl;
//data transfer performance test
// array->dirty();
# endif
}
} ;
//do not forget to set OSG_FILE_PATH to default OSG-Data and make sure the new shaders are copied there under"shaders"
class ComputeNode : public osg : : PositionAttitudeTransform
{
public :
osg : : ref_ptr < osg : : Program > _computeProgram ;
osg : : ref_ptr < osg : : Shader > _computeShader ; //compute and write position data in SSBO
osg : : ref_ptr < osg : : Shader > _vertexShader ; //reading position data from SSBO (OBS!: make sure glMemoryBuffer() is syncing this)
osg : : ref_ptr < osg : : Shader > _geometryShader ; //building a quad looking to the camera
osg : : ref_ptr < osg : : Shader > _fragmentShader ; //use false-colors etc. for making your data visible
osg : : ref_ptr < osg : : Node > _helperNode ; // coordinate system node
ref_ptr < osg : : ShaderStorageBufferObject > _ssbo ;
ref_ptr < osg : : ShaderStorageBufferBinding > _ssbb ;
GLfloat * _data ; // some data we upload to GPU, initialised with random values
osg : : ref_ptr < FloatArray > _dataArray ; //
osg : : ref_ptr < osg : : Group > _computationResultsRenderGroup ;
osg : : ref_ptr < osg : : Program > _computationResultsRenderProgram ;
osg : : ref_ptr < osg : : StateSet > _computationResultsRenderStateSet ;
std : : string _computeShaderSourcePath ;
std : : string _vertexShaderSourcePath ;
std : : string _geometryShaderSourcePath ;
std : : string _fragmentShaderSourcePath ;
void addHelperGeometry ( ) ;
void addDataMonitor ( osg : : Vec3 placement , osg : : Vec3 relativePlacement , float scale , Channel channel , BufferOffset shaderBufferOffset , std : : string labelcaption , float minDataRange , float maxDataRange ) ;
void addComputationResultsRenderTree ( ) ;
void initComputingSetup ( ) ;
ComputeNode ( )
{
const char * envOsgFilePath = getenv ( " OSG_FILE_PATH " ) ;
std : : stringstream computeshaderpath ; computeshaderpath < < envOsgFilePath < < " /shaders/osgssboComputeShader.cs " ;
_computeShaderSourcePath = computeshaderpath . str ( ) ;
std : : stringstream vertexshaderpath ; vertexshaderpath < < envOsgFilePath < < " /shaders/osgssboVertexShader.vs " ;
_vertexShaderSourcePath = vertexshaderpath . str ( ) ;
std : : stringstream geometryshaderpath ; geometryshaderpath < < envOsgFilePath < < " /shaders/osgssboGeometryShader.gs " ;
_geometryShaderSourcePath = geometryshaderpath . str ( ) ;
std : : stringstream fragmentshaderpath ; fragmentshaderpath < < envOsgFilePath < < " /shaders/osgssboFragmentShader.fs " ;
_fragmentShaderSourcePath = fragmentshaderpath . str ( ) ;
}
} ;
class ComputeNodeUpdateCallback : public osg : : NodeCallback
{
public :
ComputeNode * _computeNode ;
osg : : Timer_t _prevShaderUpdateTime ;
osg : : Timer _timer ;
ComputeNodeUpdateCallback ( ) { }
ComputeNodeUpdateCallback ( ComputeNode * computeNode )
{
_computeNode = computeNode ;
_prevShaderUpdateTime = 0 ;
}
virtual void operator ( ) ( osg : : Node * node , osg : : NodeVisitor * nv )
{
osg : : Timer_t currTime = _timer . tick ( ) ;
if ( _timer . delta_s ( _prevShaderUpdateTime , currTime ) > 1.0 ) //one second interval for shader-changed-do-reload check
{
osg : : ref_ptr < osg : : Shader > reloadedshader ;
std : : string runningSource ;
std : : string reloadedstring ;
if ( _computeNode - > _computeShader . valid ( ) )
{
runningSource = _computeNode - > _computeShader - > getShaderSource ( ) ;
reloadedshader = osg : : Shader : : readShaderFile ( osg : : Shader : : COMPUTE , _computeNode - > _computeShaderSourcePath ) ;
reloadedstring = reloadedshader - > getShaderSource ( ) ;
if ( ! osgDB : : equalCaseInsensitive ( runningSource . c_str ( ) , reloadedstring . c_str ( ) ) )
{
_computeNode - > _computeProgram - > removeShader ( _computeNode - > _computeShader . get ( ) ) ;
_computeNode - > _computeShader = reloadedshader . get ( ) ;
_computeNode - > _computeProgram - > addShader ( _computeNode - > _computeShader . get ( ) ) ;
}
}
if ( _computeNode - > _vertexShader . valid ( ) )
{
runningSource = _computeNode - > _vertexShader - > getShaderSource ( ) ;
reloadedshader = osg : : Shader : : readShaderFile ( osg : : Shader : : VERTEX , _computeNode - > _vertexShaderSourcePath ) ;
reloadedstring = reloadedshader - > getShaderSource ( ) ;
if ( ! osgDB : : equalCaseInsensitive ( runningSource . c_str ( ) , reloadedstring . c_str ( ) ) )
{
_computeNode - > _computationResultsRenderProgram - > removeShader ( _computeNode - > _vertexShader . get ( ) ) ;
_computeNode - > _vertexShader = reloadedshader . get ( ) ;
_computeNode - > _computationResultsRenderProgram - > addShader ( _computeNode - > _vertexShader . get ( ) ) ;
}
}
if ( _computeNode - > _geometryShader . valid ( ) )
{
runningSource = _computeNode - > _geometryShader - > getShaderSource ( ) ;
reloadedshader = osg : : Shader : : readShaderFile ( osg : : Shader : : GEOMETRY , _computeNode - > _geometryShaderSourcePath ) ;
reloadedstring = reloadedshader - > getShaderSource ( ) ;
if ( ! osgDB : : equalCaseInsensitive ( runningSource . c_str ( ) , reloadedstring . c_str ( ) ) )
{
_computeNode - > _computationResultsRenderProgram - > removeShader ( _computeNode - > _geometryShader . get ( ) ) ;
_computeNode - > _geometryShader = reloadedshader . get ( ) ;
_computeNode - > _computationResultsRenderProgram - > addShader ( _computeNode - > _geometryShader . get ( ) ) ;
}
}
if ( _computeNode - > _fragmentShader . valid ( ) )
{
runningSource = _computeNode - > _fragmentShader - > getShaderSource ( ) ;
reloadedshader = osg : : Shader : : readShaderFile ( osg : : Shader : : FRAGMENT , _computeNode - > _fragmentShaderSourcePath ) ;
reloadedstring = reloadedshader - > getShaderSource ( ) ;
if ( ! osgDB : : equalCaseInsensitive ( runningSource . c_str ( ) , reloadedstring . c_str ( ) ) )
{
_computeNode - > _computationResultsRenderProgram - > removeShader ( _computeNode - > _fragmentShader . get ( ) ) ;
_computeNode - > _fragmentShader = reloadedshader . get ( ) ;
_computeNode - > _computationResultsRenderProgram - > addShader ( _computeNode - > _fragmentShader . get ( ) ) ;
}
}
_prevShaderUpdateTime = _timer . tick ( ) ;
}
traverse ( node , nv ) ;
}
} ;
//set OSG_FILE_PATH for loading axes.osgt
void ComputeNode : : addHelperGeometry ( )
{
_helperNode = osgDB : : readNodeFile ( " axes.osgt " ) ;
if ( _helperNode . valid ( ) )
{
addChild ( _helperNode . get ( ) ) ;
}
//osg::PositionAttitudeTransform* pat = new osg::PositionAttitudeTransform;
//pat->setPosition(osg::Vec3(0.5, 0, 0.5));
//osg::Geode *sphereGeode = new osg::Geode;
//float radius = 0.5f;
//osg::TessellationHints* hints = new osg::TessellationHints;
//hints->setDetailRatio(0.9f);
//osg::ShapeDrawable* sphere = new osg::ShapeDrawable(new osg::Sphere(osg::Vec3(0.0f, 0.0f, 0.0f), radius), hints);
//sphereGeode->addDrawable(sphere);
//sphere->setColor(osg::Vec4(0, 1, 0, 0.1));
//osg::StateSet* stateset = sphereGeode->getOrCreateStateSet();
//osg::BlendFunc *blend = new osg::BlendFunc;
//blend->setFunction(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA);
//stateset->setAttributeAndModes(blend, osg::StateAttribute::ON);
//pat->addChild(sphereGeode);
//addChild(pat);
}
void ComputeNode : : addDataMonitor ( osg : : Vec3 placement , osg : : Vec3 relativePlacement , float scale , Channel colorchannel , BufferOffset shaderStorageBufferOffset , std : : string labelCaption , float minDataRange , float maxDataRange )
{
osg : : PositionAttitudeTransform * pat = new osg : : PositionAttitudeTransform ;
pat - > setPosition ( relativePlacement ) ;
addChild ( pat ) ;
osg : : Geometry * geom ;
if ( NUM_ELEMENTS_X > = NUM_ELEMENTS_Y )
{
float ratio = ( float ) ( ( float ) NUM_ELEMENTS_Y / ( float ) NUM_ELEMENTS_X ) ;
geom = osg : : createTexturedQuadGeometry ( placement , osg : : Vec3 ( 1.0f * scale , 0.0f , 0.0f ) , osg : : Vec3 ( 0.0f , 0.0f , ratio * 1.0f * scale ) ) ;
}
else
{
float ratio = ( float ) ( ( float ) NUM_ELEMENTS_X / ( float ) NUM_ELEMENTS_Y ) ;
geom = osg : : createTexturedQuadGeometry ( placement , osg : : Vec3 ( ratio * 1.0f * scale , 0.0f , 0.0f ) , osg : : Vec3 ( 0.0f , 0.0f , 1.0f * scale ) ) ;
}
geom - > setVertexAttribArray ( 1 , geom - > getTexCoordArray ( 0 ) , osg : : Array : : BIND_PER_VERTEX ) ;
osg : : ref_ptr < osg : : Geode > quad = new osg : : Geode ;
quad - > addDrawable ( geom ) ;
quad - > setStateSet ( getOrCreateStateSet ( ) ) ;
pat - > addChild ( quad . get ( ) ) ;
static const char * vertexShaderSrcChannelMonitor = {
" #version 430 \n "
" uniform int numRows; \n "
" uniform int numCols; \n "
" uniform float osg_FrameTime; \n "
" uniform mat4 osg_ProjectionMatrix; \n "
" uniform mat4 osg_ModelViewMatrix; \n "
" out vec2 texCoordFromVertexShader; \n "
" struct particle{ float x; float y; float z; float w;}; "
" layout (location = 0) in vec3 vertexpos; \n "
" attribute vec2 tex_coords; \n "
" void main() { \n "
" texCoordFromVertexShader.xy = tex_coords.xy; gl_Position = ( osg_ProjectionMatrix * osg_ModelViewMatrix * vec4(vertexpos.x,vertexpos.y,vertexpos.z,1) ); \n "
" } \n "
} ;
std : : stringstream fragmentshaderstringstreamChannelMonitor ;
fragmentshaderstringstreamChannelMonitor < < " #version 430 \n " ;
fragmentshaderstringstreamChannelMonitor < < " uniform int numRows; \n " ;
fragmentshaderstringstreamChannelMonitor < < " uniform int numCols; \n " ;
fragmentshaderstringstreamChannelMonitor < < " uniform float dataRangeMin; \n " ;
fragmentshaderstringstreamChannelMonitor < < " uniform float dataRangeMax; \n " ;
fragmentshaderstringstreamChannelMonitor < < " in vec2 texCoordFromVertexShader; \n " ;
fragmentshaderstringstreamChannelMonitor < < " struct particle{ float x; float y; float z; float w;}; " ;
fragmentshaderstringstreamChannelMonitor < < " layout(std140, binding=0) coherent buffer particles{particle p[];}; " ;
fragmentshaderstringstreamChannelMonitor < < " \n " ;
fragmentshaderstringstreamChannelMonitor < < " void main(void) \n " ;
fragmentshaderstringstreamChannelMonitor < < " { \n " ;
fragmentshaderstringstreamChannelMonitor < < " ivec2 storePos = ivec2(numRows*texCoordFromVertexShader.x, numCols*texCoordFromVertexShader.y); particle particleData = p[ " < < shaderStorageBufferOffset * NUM_ELEMENTS_X * NUM_ELEMENTS_Y < < " + (storePos.x*numRows + storePos.y)]; " ;
//fragmentshaderstringstreamChannelMonitor << " memoryBarrierBuffer(); \n";
fragmentshaderstringstreamChannelMonitor < < " float dataRangeMultiplier = 1.0 / abs(dataRangeMax - dataRangeMin); \n " ;
switch ( colorchannel )
{
case RED_CHANNEL :
{
fragmentshaderstringstreamChannelMonitor < < " vec4 color; color.x = 0.5+dataRangeMultiplier*particleData.x; color.y =0.0; color.z = 0.0; color.w = 1.0; gl_FragColor = color; \n " ;
break ;
}
case GREEN_CHANNEL :
{
fragmentshaderstringstreamChannelMonitor < < " vec4 color; color.x = 0.0; color.y = 0.5+dataRangeMultiplier*particleData.y; color.z = 0.0; color.w = 1.0; gl_FragColor = color; \n " ;
break ;
}
case BLUE_CHANNEL :
{
fragmentshaderstringstreamChannelMonitor < < " vec4 color; color.x = 0.0; color.y = 0.0; color.z = 0.5+dataRangeMultiplier*particleData.z; color.w = 0.0 ; gl_FragColor = color; \n " ;
break ;
}
case ALPHA_CHANNEL :
{
fragmentshaderstringstreamChannelMonitor < < " vec4 color; color.x = 0.5+dataRangeMultiplier*particleData.w; color.y = 0.5+dataRangeMultiplier*particleData.w; color.z = 0.5+dataRangeMultiplier*particleData.w; color.w = 0.5+0.5*particleData.w; gl_FragColor = color; \n " ;
break ;
}
case RGB_CHANNEL :
{
fragmentshaderstringstreamChannelMonitor < < " vec4 color; color.x = 0.5+dataRangeMultiplier*particleData.x; color.y = 0.5+dataRangeMultiplier*particleData.y; color.z = 0.5+dataRangeMultiplier*particleData.z; color.w = 1.0; gl_FragColor = color; \n " ;
break ;
}
2014-12-11 02:23:32 +08:00
case RGBA_CHANNEL :
{
fragmentshaderstringstreamChannelMonitor < < " vec4 color; color.x = 0.5+dataRangeMultiplier*particleData.x; color.y = 0.5+dataRangeMultiplier*particleData.y; color.z = 0.5+dataRangeMultiplier*particleData.z; color.w = 0.5+0.5*particleData.w; gl_FragColor = color; \n " ;
break ;
}
2014-12-10 20:23:04 +08:00
}
fragmentshaderstringstreamChannelMonitor < < " } \n " ;
osg : : Program * program = new osg : : Program ;
program - > addShader ( new osg : : Shader ( osg : : Shader : : VERTEX , vertexShaderSrcChannelMonitor ) ) ;
program - > addShader ( new osg : : Shader ( osg : : Shader : : FRAGMENT , fragmentshaderstringstreamChannelMonitor . str ( ) . c_str ( ) ) ) ;
program - > addBindAttribLocation ( " tex_coords " , 1 ) ;
osg : : StateSet * ss = geom - > getOrCreateStateSet ( ) ;
ss - > setAttributeAndModes ( program , osg : : StateAttribute : : ON ) ;
ss - > addUniform ( new osg : : Uniform ( " numRows " , ( int ) NUM_ELEMENTS_X ) ) ;
ss - > addUniform ( new osg : : Uniform ( " numCols " , ( int ) NUM_ELEMENTS_Y ) ) ;
ss - > addUniform ( new osg : : Uniform ( " dataRangeMin " , ( float ) minDataRange ) ) ;
ss - > addUniform ( new osg : : Uniform ( " dataRangeMax " , ( float ) maxDataRange ) ) ;
ss - > setMode ( GL_LIGHTING , osg : : StateAttribute : : OFF ) ;
//add a label
osgText : : Text * text = new osgText : : Text ;
osgText : : Font * font = osgText : : readFontFile ( " fonts/arial.ttf " ) ;
text - > setFont ( font ) ;
text - > setColor ( osg : : Vec4 ( 1 , 1 , 1 , 1 ) ) ;
text - > setCharacterSize ( 0.1 * scale ) ;
text - > setPosition ( placement + osg : : Vec3 ( 0.05 , 0.05 , 0 ) ) ;
pat - > setName ( labelCaption ) ;
text - > setText ( pat - > getName ( ) ) ;
text - > setBackdropType ( osgText : : Text : : OUTLINE ) ;
text - > setBackdropImplementation ( osgText : : Text : : POLYGON_OFFSET ) ;
text - > setBackdropOffset ( 0.05f ) ;
text - > setBackdropColor ( osg : : Vec4 ( 0.0f , 0.0f , 0.0f , 1.0f ) ) ;
quad - > addDrawable ( text ) ;
pat - > addChild ( quad . get ( ) ) ;
}
//compute texture image , taken from osgspotlight
osg : : Image * createSpotLightImage ( const osg : : Vec4 & centerColour , const osg : : Vec4 & backgroudColour , unsigned int size , float power )
{
osg : : Image * image = new osg : : Image ;
image - > allocateImage ( size , size , 1 ,
GL_RGBA , GL_UNSIGNED_BYTE ) ;
float mid = ( float ( size ) - 1 ) * 0.5f ;
float div = 2.0f / float ( size ) ;
for ( unsigned int r = 0 ; r < size ; + + r )
{
unsigned char * ptr = image - > data ( 0 , r , 0 ) ;
for ( unsigned int c = 0 ; c < size ; + + c )
{
float dx = ( float ( c ) - mid ) * div ;
float dy = ( float ( r ) - mid ) * div ;
float r = powf ( 1.0f - sqrtf ( dx * dx + dy * dy ) , power ) ;
if ( r < 0.0f ) r = 0.0f ;
osg : : Vec4 color = centerColour * r + backgroudColour * ( 1.0f - r ) ;
* ptr + + = ( unsigned char ) ( ( color [ 0 ] ) * 255.0f ) ;
* ptr + + = ( unsigned char ) ( ( color [ 1 ] ) * 255.0f ) ;
* ptr + + = ( unsigned char ) ( ( color [ 2 ] ) * 255.0f ) ;
* ptr + + = ( unsigned char ) ( ( color [ 3 ] ) * 255.0f ) ;
}
}
return image ;
}
void ComputeNode : : addComputationResultsRenderTree ( )
{
_computationResultsRenderProgram = new osg : : Program ;
_vertexShader = osg : : Shader : : readShaderFile ( osg : : Shader : : VERTEX , _vertexShaderSourcePath ) ;
_computationResultsRenderProgram - > addShader ( _vertexShader . get ( ) ) ;
_geometryShader = osg : : Shader : : readShaderFile ( osg : : Shader : : GEOMETRY , _geometryShaderSourcePath ) ;
_computationResultsRenderProgram - > addShader ( _geometryShader . get ( ) ) ;
_fragmentShader = osg : : Shader : : readShaderFile ( osg : : Shader : : FRAGMENT , _fragmentShaderSourcePath ) ;
_computationResultsRenderProgram - > addShader ( _fragmentShader . get ( ) ) ;
_computationResultsRenderProgram - > addBindAttribLocation ( " tex_coords " , 1 ) ;
_computationResultsRenderGroup = new osg : : Group ;
_computationResultsRenderGroup - > setDataVariance ( osg : : Object : : DYNAMIC ) ;
_computationResultsRenderStateSet = _computationResultsRenderGroup - > getOrCreateStateSet ( ) ;
_computationResultsRenderStateSet - > setRenderingHint ( osg : : StateSet : : TRANSPARENT_BIN ) ;
osg : : PointSprite * sprite = new osg : : PointSprite ;
int texture_unit = 0 ;
_computationResultsRenderStateSet - > setTextureAttributeAndModes ( texture_unit , sprite , osg : : StateAttribute : : ON ) ;
2014-12-11 02:23:32 +08:00
_computationResultsRenderStateSet - > setAttributeAndModes ( _computationResultsRenderProgram . get ( ) , osg : : StateAttribute : : ON ) ;
2014-12-10 20:23:04 +08:00
_computationResultsRenderStateSet - > addUniform ( new osg : : Uniform ( " particleTexture " , texture_unit ) ) ;
_computationResultsRenderStateSet - > addUniform ( new osg : : Uniform ( " numRows " , ( int ) NUM_ELEMENTS_X ) ) ;
_computationResultsRenderStateSet - > addUniform ( new osg : : Uniform ( " numCols " , ( int ) NUM_ELEMENTS_Y ) ) ;
_computationResultsRenderStateSet - > setMode ( GL_POINT_SMOOTH , osg : : StateAttribute : : ON ) ;
_computationResultsRenderStateSet - > setMode ( GL_VERTEX_PROGRAM_POINT_SIZE_ARB , osg : : StateAttribute : : ON ) ;
_computationResultsRenderStateSet - > setMode ( GL_ALPHA_TEST , osg : : StateAttribute : : ON ) ;
_computationResultsRenderStateSet - > setMode ( GL_LIGHTING , osg : : StateAttribute : : OFF ) ;
osg : : Texture2D * tex = new osg : : Texture2D ( ) ;
osg : : Image * particleImage = createSpotLightImage ( osg : : Vec4 ( 1 , 0 , 0 , 1 ) , osg : : Vec4 ( 0.5 , 0 , 0 , 0.0 ) , 32 , 0.7 ) ;
if ( particleImage )
{
tex - > setImage ( particleImage ) ;
}
_computationResultsRenderStateSet - > setTextureAttributeAndModes ( texture_unit , tex , osg : : StateAttribute : : ON ) ;
osg : : BlendFunc * blend = new osg : : BlendFunc ;
if ( false ) //emissive particles
{
blend - > setFunction ( osg : : BlendFunc : : SRC_ALPHA , osg : : BlendFunc : : ONE ) ;
}
else
{
blend - > setFunction ( osg : : BlendFunc : : SRC_ALPHA , osg : : BlendFunc : : ONE_MINUS_SRC_ALPHA ) ;
}
_computationResultsRenderStateSet - > setAttributeAndModes ( blend , osg : : StateAttribute : : ON ) ;
osg : : Depth * depth = new osg : : Depth ;
depth - > setRange ( 0.0f , 0.0f ) ;
depth - > setFunction ( osg : : Depth : : ALWAYS ) ;
depth - > setWriteMask ( false ) ;
depth - > setFunction ( osg : : Depth : : ALWAYS ) ;
_computationResultsRenderStateSet - > setAttributeAndModes ( depth , osg : : StateAttribute : : OFF ) ;
osg : : Geode * particleGeode = new osg : : Geode ;
unsigned int numVertices = NUM_ELEMENTS_X * NUM_ELEMENTS_Y ;
osg : : Geometry * particleGeometry = new osg : : Geometry ;
particleGeometry - > setUseDisplayList ( false ) ;
particleGeometry - > setUseVertexBufferObjects ( true ) ;
osg : : Vec3Array * vertexarray = new osg : : Vec3Array ;
osg : : Vec2Array * tcoords = new osg : : Vec2Array ;
osg : : Vec2 bottom_texcoord ( 0.0f , 0.0f ) ;
osg : : Vec2 dx_texcoord ( 1.0f / ( float ) ( NUM_ELEMENTS_X ) , 0.0f ) ;
osg : : Vec2 dy_texcoord ( 0.0f , 1.0f / ( float ) ( NUM_ELEMENTS_Y ) ) ;
for ( int i = 0 ; i < NUM_ELEMENTS_X ; i + + )
{
osg : : Vec2 texcoord = bottom_texcoord + dy_texcoord * ( float ) i ;
for ( int j = 0 ; j < NUM_ELEMENTS_Y ; j + + )
{
vertexarray - > push_back ( osg : : Vec3 ( texcoord . x ( ) , texcoord . y ( ) , 0.0 ) ) ;
tcoords - > push_back ( osg : : Vec2 ( texcoord . x ( ) , texcoord . y ( ) ) ) ;
texcoord + = dx_texcoord ;
}
}
particleGeometry - > setVertexArray ( vertexarray ) ;
particleGeometry - > addPrimitiveSet ( new osg : : DrawArrays ( GL_POINTS , 0 , numVertices ) ) ;
particleGeometry - > setTexCoordArray ( 0 , tcoords ) ;
//this glMemoryBarrier thing... not sure if we could better do instanced drawing? all the data is in Shader Storage Buffer..
particleGeometry - > setVertexAttribArray ( 1 , particleGeometry - > getTexCoordArray ( 0 ) , osg : : Array : : BIND_PER_VERTEX ) ;
_computationResultsRenderGroup - > addChild ( particleGeode ) ;
particleGeode - > addDrawable ( particleGeometry ) ;
2014-12-11 02:23:32 +08:00
addChild ( _computationResultsRenderGroup . get ( ) ) ;
2014-12-10 20:23:04 +08:00
}
void ComputeNode : : initComputingSetup ( )
{
_computeProgram = new osg : : Program ;
_computeProgram - > setComputeGroups ( ( NUM_ELEMENTS_X / WORK_GROUP_SIZE ) < = 1 ? 1 : ( NUM_ELEMENTS_X / WORK_GROUP_SIZE ) , ( NUM_ELEMENTS_Y / WORK_GROUP_SIZE ) < = 1 ? 1 : ( NUM_ELEMENTS_Y / WORK_GROUP_SIZE ) , 1 ) ;
_computeShader = osg : : Shader : : readShaderFile ( osg : : Shader : : COMPUTE , _computeShaderSourcePath ) ;
_computeProgram - > addShader ( _computeShader . get ( ) ) ;
setDataVariance ( osg : : Object : : DYNAMIC ) ;
osg : : StateSet * statesetComputation = getOrCreateStateSet ( ) ;
statesetComputation - > setAttributeAndModes ( _computeProgram . get ( ) ) ;
statesetComputation - > addUniform ( new osg : : Uniform ( " numCols " , ( int ) NUM_ELEMENTS_X ) ) ;
statesetComputation - > addUniform ( new osg : : Uniform ( " numRows " , ( int ) NUM_ELEMENTS_Y ) ) ;
statesetComputation - > setMode ( GL_LIGHTING , osg : : StateAttribute : : OFF ) ;
//blocksize
int numParticles = NUM_ELEMENTS_X * NUM_ELEMENTS_Y ;
const unsigned blockSize = numParticles * __numChannels * __numDataValuesPerChannel * sizeof ( GLfloat ) ;
//init all the particle data array
int idx = 0 ;
_data = new GLfloat [ NUM_ELEMENTS_X * NUM_ELEMENTS_Y * __numChannels * __numDataValuesPerChannel ] ;
_dataArray = new FloatArray ;
//init the data array somehow, this way all is stored in one BufferObject. maybe better using multiple buffers instead? not sure what is faster and better for threading
for ( int d = 0 ; d < __numDataValuesPerChannel ; + + d )
{
for ( int i = 0 ; i < NUM_ELEMENTS_X ; + + i )
{
for ( int j = 0 ; j < NUM_ELEMENTS_Y ; + + j )
{
for ( int k = 0 ; k < __numChannels ; + + k )
{
switch ( k )
{
case ( RED_CHANNEL ) :
{
if ( ( d = = POSITION_NOW_OFFSET ) | | ( d = = POSITION_OLD_OFFSET ) | | ( d = = POSITION_INIT_OFFSET ) ) //position
{
* _data = random ( 0.25 , 0.75 ) ;
}
if ( ( d = = VELOCITY_NOW_OFFSET ) | | ( d = = VELOCITY_OLD_OFFSET ) | | ( d = = VELOCITY_INIT_OFFSET ) ) //velocity
{
* _data = random ( - 2.4 , 2.4 ) ;
}
if ( d = = ACCELERATION_OFFSET ) //acceleration
{
* _data = random ( - 3.0 , 3.0 ) ;
}
if ( d = = PROPERTIES_OFFSET ) //property particle mass (compute shader is computing sphere mass from radius instead)
{
* _data = random ( 0.2 , 15.0 ) ;
}
break ;
}
case ( GREEN_CHANNEL ) :
{
if ( ( d = = POSITION_NOW_OFFSET ) | | ( d = = POSITION_OLD_OFFSET ) | | ( d = = POSITION_INIT_OFFSET ) ) //position
{
* _data = random ( 0.25 , 0.75 ) ;
}
if ( ( d = = VELOCITY_NOW_OFFSET ) | | ( d = = VELOCITY_OLD_OFFSET ) | | ( d = = VELOCITY_INIT_OFFSET ) ) //velocity
{
* _data = random ( - 2.4 , 2.4 ) ;
}
if ( d = = ACCELERATION_OFFSET ) //acceleration
{
* _data = random ( - 3.0 , 3.0 ) ;
}
if ( d = = PROPERTIES_OFFSET ) //property particle radius
{
* _data = random ( 0.07 , 0.219 ) ;
}
break ;
}
case ( BLUE_CHANNEL ) :
{
if ( ( d = = POSITION_NOW_OFFSET ) | | ( d = = POSITION_OLD_OFFSET ) | | ( d = = POSITION_INIT_OFFSET ) ) //position
{
* _data = random ( 0.25 , 0.75 ) ;
}
if ( ( d = = VELOCITY_NOW_OFFSET ) | | ( d = = VELOCITY_OLD_OFFSET ) | | ( d = = VELOCITY_INIT_OFFSET ) ) //velocity
{
* _data = random ( - 2.4 , 2.4 ) ;
}
if ( d = = ACCELERATION_OFFSET ) //acceleration
{
* _data = random ( - 3.0 , 3.0 ) ;
}
if ( d = = PROPERTIES_OFFSET ) //place for some other property
{
* _data = random ( 0.0 , 0.0 ) ;
}
break ;
}
case ( ALPHA_CHANNEL ) :
{
if ( ( d = = POSITION_NOW_OFFSET ) | | ( d = = POSITION_OLD_OFFSET ) | | ( d = = POSITION_INIT_OFFSET ) ) //position
{
* _data = random ( 1.0 , 1.0 ) ;
}
if ( ( d = = VELOCITY_NOW_OFFSET ) | | ( d = = VELOCITY_OLD_OFFSET ) | | ( d = = VELOCITY_INIT_OFFSET ) ) //velocity
{
* _data = random ( - 2.4 , 2.4 ) ;
}
if ( d = = ACCELERATION_OFFSET ) //acceleration
{
//*_data = random(1.0, 1.0);
* _data = random ( 0.0 , 0.0 ) ;
}
if ( d = = PROPERTIES_OFFSET ) //place for some other property
{
* _data = random ( 0.3 , 0.3 ) ;
}
break ;
}
}
_dataArray - > push_back ( * _data ) ;
_data + + ;
idx + + ;
}
}
}
}
_ssbo = new osg : : ShaderStorageBufferObject ;
_dataArray - > setBufferObject ( _ssbo . get ( ) ) ;
_ssbb = new osg : : ShaderStorageBufferBinding ( 0 , _ssbo . get ( ) , 0 , blockSize ) ;
statesetComputation - > setAttributeAndModes ( _ssbb . get ( ) , osg : : StateAttribute : : ON ) ;
//option, do something useful with data or test the transfer speed
//_ssbb->setUpdateCallback(new ShaderStorageBufferCallback);
//adding a quad , visualizing data in buffer
addDataMonitor ( osg : : Vec3 ( 0 , - 1 , 0 ) , osg : : Vec3 ( SUB_PLACEMENT_OFFSET_HORIZONTAL * 0 , - SUB_PLACEMENT_OFFSET_VERTICAL * - 2.0 , SUB_PLACEMENT_OFFSET_HORIZONTAL * 0 ) , 1.0 , RGB_CHANNEL , POSITION_NOW_OFFSET , " X,Y,Z - PositionNow " , - 1.0 , 1.0 ) ;
//the coord from default dataset
addHelperGeometry ( ) ;
addComputationResultsRenderTree ( ) ;
}
//taken from osgdistorsion example for getting it nice on screen with antialiasing
osg : : Node * createPrerenderSubgraph ( osg : : Node * subgraph , const osg : : Vec4 & clearColour )
{
osg : : Group * prerenderNode = new osg : : Group ;
unsigned int tex_width = PRERENDER_WIDTH ;
unsigned int tex_height = PRERENDER_HEIGHT ;
osg : : Texture2D * texture = new osg : : Texture2D ;
texture - > setTextureSize ( tex_width , tex_height ) ;
texture - > setInternalFormat ( GL_RGBA ) ;
texture - > setFilter ( osg : : Texture2D : : MIN_FILTER , osg : : Texture2D : : LINEAR ) ;
texture - > setFilter ( osg : : Texture2D : : MAG_FILTER , osg : : Texture2D : : LINEAR ) ;
{
osg : : Camera * prerenderCamera = new osg : : Camera ;
prerenderCamera - > setClearColor ( clearColour ) ;
prerenderCamera - > setClearMask ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ;
prerenderCamera - > setReferenceFrame ( osg : : Transform : : RELATIVE_RF ) ;
prerenderCamera - > setProjectionMatrix ( osg : : Matrixd : : identity ( ) ) ;
prerenderCamera - > setViewMatrix ( osg : : Matrixd : : identity ( ) ) ;
prerenderCamera - > setViewport ( 0 , 0 , tex_width , tex_height ) ;
prerenderCamera - > setRenderOrder ( osg : : Camera : : PRE_RENDER ) ;
prerenderCamera - > setRenderTargetImplementation ( osg : : Camera : : FRAME_BUFFER_OBJECT ) ;
prerenderCamera - > attach ( osg : : Camera : : COLOR_BUFFER0 , texture , 0 , 0 , false , PRERENDER_ANTIALIASINGMULTISAMPLES , PRERENDER_ANTIALIASINGMULTISAMPLES ) ;
prerenderCamera - > addChild ( subgraph ) ;
prerenderNode - > addChild ( prerenderCamera ) ;
}
{
osg : : Geometry * polyGeom = new osg : : Geometry ( ) ;
polyGeom - > setSupportsDisplayList ( false ) ;
osg : : Vec3 origin ( 0.0f , 0.0f , 0.0f ) ;
osg : : Vec3 xAxis ( 1.0f , 0.0f , 0.0f ) ;
osg : : Vec3 yAxis ( 0.0f , 1.0f , 0.0f ) ;
float height = 1024.0f ;
float width = 1280.0f ;
int noSteps = 3 ;
osg : : Vec3Array * vertices = new osg : : Vec3Array ;
osg : : Vec2Array * texcoords = new osg : : Vec2Array ;
osg : : Vec4Array * colors = new osg : : Vec4Array ;
osg : : Vec3 bottom = origin ;
osg : : Vec3 dx = xAxis * ( width / ( ( float ) ( noSteps - 1 ) ) ) ;
osg : : Vec3 dy = yAxis * ( height / ( ( float ) ( noSteps - 1 ) ) ) ;
osg : : Vec2 bottom_texcoord ( 0.0f , 0.0f ) ;
osg : : Vec2 dx_texcoord ( 1.0f / ( float ) ( noSteps - 1 ) , 0.0f ) ;
osg : : Vec2 dy_texcoord ( 0.0f , 1.0f / ( float ) ( noSteps - 1 ) ) ;
int i , j ;
for ( i = 0 ; i < noSteps ; + + i )
{
osg : : Vec3 cursor = bottom + dy * ( float ) i ;
osg : : Vec2 texcoord = bottom_texcoord + dy_texcoord * ( float ) i ;
for ( j = 0 ; j < noSteps ; + + j )
{
vertices - > push_back ( cursor ) ;
texcoords - > push_back ( osg : : Vec2 ( ( sin ( texcoord . x ( ) * osg : : PI - osg : : PI * 0.5 ) + 1.0f ) * 0.5f , ( sin ( texcoord . y ( ) * osg : : PI - osg : : PI * 0.5 ) + 1.0f ) * 0.5f ) ) ;
colors - > push_back ( osg : : Vec4 ( 1.0f , 1.0f , 1.0f , 1.0f ) ) ;
cursor + = dx ;
texcoord + = dx_texcoord ;
}
}
polyGeom - > setVertexArray ( vertices ) ;
polyGeom - > setColorArray ( colors , osg : : Array : : BIND_PER_VERTEX ) ;
polyGeom - > setTexCoordArray ( 0 , texcoords ) ;
for ( i = 0 ; i < noSteps - 1 ; + + i )
{
osg : : DrawElementsUShort * elements = new osg : : DrawElementsUShort ( osg : : PrimitiveSet : : QUAD_STRIP ) ;
for ( j = 0 ; j < noSteps ; + + j )
{
elements - > push_back ( j + ( i + 1 ) * noSteps ) ;
elements - > push_back ( j + ( i ) * noSteps ) ;
}
polyGeom - > addPrimitiveSet ( elements ) ;
}
osg : : StateSet * stateset = polyGeom - > getOrCreateStateSet ( ) ;
stateset - > setTextureAttributeAndModes ( 0 , texture , osg : : StateAttribute : : ON ) ;
stateset - > setMode ( GL_LIGHTING , osg : : StateAttribute : : OFF ) ;
osg : : Geode * geode = new osg : : Geode ( ) ;
geode - > addDrawable ( polyGeom ) ;
osg : : Camera * nestedRenderCamera = new osg : : Camera ;
nestedRenderCamera - > setReferenceFrame ( osg : : Transform : : ABSOLUTE_RF ) ;
nestedRenderCamera - > setViewMatrix ( osg : : Matrix : : identity ( ) ) ;
nestedRenderCamera - > setProjectionMatrixAsOrtho2D ( 0 , 1280 , 0 , 1024 ) ;
nestedRenderCamera - > setRenderOrder ( osg : : Camera : : NESTED_RENDER ) ;
nestedRenderCamera - > addChild ( geode ) ;
prerenderNode - > addChild ( nestedRenderCamera ) ;
}
return prerenderNode ;
}
int main ( int argc , char * * argv )
{
osg : : ArgumentParser arguments ( & argc , argv ) ;
osgViewer : : Viewer viewer ;
osg : : ref_ptr < osg : : Group > scene = new osg : : Group ;
viewer . addEventHandler ( new osgGA : : StateSetManipulator ( viewer . getCamera ( ) - > getOrCreateStateSet ( ) ) ) ;
viewer . addEventHandler ( new osgViewer : : StatsHandler ) ;
viewer . addEventHandler ( new osgViewer : : WindowSizeHandler ) ;
viewer . addEventHandler ( new osgViewer : : ThreadingHandler ) ;
viewer . getCamera ( ) - > setProjectionMatrixAsPerspective ( 60.0f , 1.33333 , 0.01 , 100.0 ) ;
viewer . setCameraManipulator ( new osgGA : : TrackballManipulator ( ) ) ;
viewer . setUpViewInWindow ( 11 , 11 , 800 + 11 , 600 + 11 ) ;
//viewer.setUpViewOnSingleScreen(0); // !!
viewer . getCamera ( ) - > setClearColor ( osg : : Vec4 ( 0.3 , 0.3 , 0.3 , 1.0 ) ) ;
viewer . setThreadingModel ( osgViewer : : Viewer : : SingleThreaded ) ; // we can play with threading models later
osg : : ref_ptr < ComputeNode > computeNode = new ComputeNode ( ) ;
computeNode - > setPosition ( osg : : Vec3 ( 0 , 0 , 0 ) ) ;
2014-12-11 02:23:32 +08:00
computeNode - > setUpdateCallback ( new ComputeNodeUpdateCallback ( computeNode . get ( ) ) ) ; // on-the-fly reloading the shaders if shader source on disk is changed
2014-12-10 20:23:04 +08:00
computeNode - > initComputingSetup ( ) ;
scene - > addChild ( computeNode . get ( ) ) ;
scene - > addChild ( computeNode - > _computationResultsRenderGroup . get ( ) ) ;
# ifdef PRERENDER_HIGH_QUALITY_ANTIALIASING
viewer . setSceneData ( createPrerenderSubgraph ( scene . get ( ) , osg : : Vec4 ( 0.3 , 0.4 , 0.6 , 1 ) ) ) ;
# else
viewer . setSceneData ( scene . get ( ) ) ;
# endif
viewer . realize ( ) ;
viewer . getCamera ( ) - > getGraphicsContext ( ) - > getState ( ) - > setUseModelViewAndProjectionUniforms ( true ) ;
viewer . run ( ) ;
return 1 ;
}