1 // OpenSG Example: ComputeShader3
3 // This example shows the basic usage of the compute shader.
4 // It is a variation of the ComplexSceneManager example
5 // found in Examples/CSM/NewShader/Compute/SimpleTex.
7 // In this example a material database in form of a shader storage
8 // buffer object is used in the shader in order to color the pixels
9 // of the image differently. The setup of the shader storage buffer
10 // object is shown and the example works with a variable work
11 // group size for illustration purpose. Additionally, the use of a
12 // memory barrier at the end of the comptuation is shown.
14 #include <boost/foreach.hpp>
16 #ifdef OSG_BUILD_ACTIVE
19 #include <OSGConfig.h>
20 #include <OSGSimpleGeometry.h>
21 #include <OSGGLUTWindow.h>
22 #include <OSGSimpleSceneManager.h>
23 #include <OSGBaseFunctions.h>
24 #include <OSGTransform.h>
28 #include <OSGAlgorithmComputeElement.h>
29 #include <OSGChunkMaterial.h>
30 #include <OSGComputeShaderAlgorithm.h>
31 #include <OSGComputeShaderChunk.h>
32 #include <OSGContainerCollection.h>
33 #include <OSGFieldConnector.h>
34 #include <OSGFrameHandler.h>
35 #include <OSGGeometry.h>
37 #include <OSGImageFileHandler.h>
38 #include <OSGMaterialChunk.h>
39 #include <OSGMaterialGroup.h>
40 #include <OSGMultiPropertySSBOChunk.h>
41 #include <OSGShaderProgram.h>
42 #include <OSGShaderProgramVariables.h>
43 #include <OSGShaderVariableReal.h>
44 #include <OSGTextureObjChunk.h>
45 #include <OSGTextureEnvChunk.h>
46 #include <OSGTextureImageChunk.h>
48 #include <OSGTimeSensor.h>
49 #include <OSGTypedGeoIntegralProperty.h>
50 #include <OSGTypedGeoVectorProperty.h>
51 #include <OSGVRMLScalarInterpolator.h>
54 #include <OpenSG/OSGGLUT.h>
55 #include <OpenSG/OSGConfig.h>
56 #include <OpenSG/OSGSimpleGeometry.h>
57 #include <OpenSG/OSGGLUTWindow.h>
58 #include <OpenSG/OSGSimpleSceneManager.h>
59 #include <OpenSG/OSGBaseFunctions.h>
60 #include <OpenSG/OSGTransform.h>
61 #include <OpenSG/OSGGroup.h>
64 #include <OpenSG/OSGAlgorithmComputeElement.h>
65 #include <OpenSG/OSGChunkMaterial.h>
66 #include <OpenSG/OSGComputeShaderAlgorithm.h>
67 #include <OpenSG/OSGComputeShaderChunk.h>
68 #include <OpenSG/OSGContainerCollection.h>
69 #include <OpenSG/OSGFieldConnector.h>
70 #include <OpenSG/OSGFrameHandler.h>
71 #include <OpenSG/OSGGeometry.h>
72 #include <OpenSG/OSGImage.h>
73 #include <OpenSG/OSGImageFileHandler.h>
74 #include <OpenSG/OSGMaterialChunk.h>
75 #include <OpenSG/OSGMaterialGroup.h>
76 #include <OpenSG/OSGMultiPropertySSBOChunk.h>
77 #include <OpenSG/OSGShaderProgram.h>
78 #include <OpenSG/OSGShaderProgramVariables.h>
79 #include <OpenSG/OSGShaderVariableReal.h>
80 #include <OpenSG/OSGTextureObjChunk.h>
81 #include <OpenSG/OSGTextureEnvChunk.h>
82 #include <OpenSG/OSGTextureImageChunk.h>
83 #include <OpenSG/OSGTime.h>
84 #include <OpenSG/OSGTimeSensor.h>
85 #include <OpenSG/OSGTypedGeoIntegralProperty.h>
86 #include <OpenSG/OSGTypedGeoVectorProperty.h>
87 #include <OpenSG/OSGVRMLScalarInterpolator.h>
90 const OSG::Vec3i
work_group_count(32,32,1);
91 const OSG::Vec3i
work_group_size(16,16,1);
93 const std::size_t num_materials
= (work_group_size
.z()-1) * work_group_size
.y() * work_group_size
.x()
94 + (work_group_size
.y()-1) * work_group_size
.x()
95 + (work_group_size
.x()-1)
98 // Simple material data structure
103 : ambient (0.f
, 0.f
, 0.f
)
104 , diffuse (0.f
, 0.f
, 0.f
)
105 , specular(0.f
, 0.f
, 0.f
)
106 , emissive(0.f
, 0.f
, 0.f
)
111 OSG::Color3f ambient
;
112 OSG::Color3f diffuse
;
113 OSG::Color3f specular
;
114 OSG::Color3f emissive
;
117 OSG::Real32 shininess
;
119 static OSG::UInt32 ambient_id
;
120 static OSG::UInt32 diffuse_id
;
121 static OSG::UInt32 specular_id
;
122 static OSG::UInt32 emissive_id
;
123 static OSG::UInt32 opacity_id
;
124 static OSG::UInt32 shininess_id
;
127 OSG::UInt32
Material:: ambient_id
= 0;
128 OSG::UInt32
Material:: diffuse_id
= 0;
129 OSG::UInt32
Material:: specular_id
= 0;
130 OSG::UInt32
Material:: emissive_id
= 0;
131 OSG::UInt32
Material:: opacity_id
= 0;
132 OSG::UInt32
Material::shininess_id
= 0;
134 typedef std::vector
<Material
> VecMaterialsT
; // multiple materials
136 VecMaterialsT
initialize_materials(std::size_t num
) // helper to create materials
138 VecMaterialsT
mat(num
);
140 for (std::size_t i
= 0; i
< num
; ++i
)
142 mat
[i
].ambient
= OSG::Color3f(0.001f
, 0.001f
, 0.001f
);
143 mat
[i
].diffuse
.setRandom();
144 mat
[i
].specular
= OSG::Color3f(0.9f
, 0.9f
, 0.9f
);
145 mat
[i
].emissive
= OSG::Color3f(0.0f
, 0.0f
, 0.0f
);
146 mat
[i
].opacity
= 1.f
;
147 mat
[i
].shininess
= 100.f
;
153 VecMaterialsT materials
= initialize_materials(num_materials
); // the material database
155 OSG::MultiPropertySSBOChunkTransitPtr
create_material_database_state(const VecMaterialsT
& vMaterials
)
157 OSG::MultiPropertySSBOChunkRefPtr materialChunk
= OSG::MultiPropertySSBOChunk::create();
159 OSG::UInt32 vec3_id
, float_id
;
161 vec3_id
= materialChunk
->addMember(OSG::MultiPropertySSBOChunk:: VEC3_T
, 4);
162 float_id
= materialChunk
->addMember(OSG::MultiPropertySSBOChunk::FLOAT_T
, 2);
164 materialChunk
->setUsage(GL_STATIC_DRAW
);
166 Material:: ambient_id
= vec3_id
++;
167 Material:: diffuse_id
= vec3_id
++;
168 Material:: specular_id
= vec3_id
++;
169 Material:: emissive_id
= vec3_id
;
171 Material:: opacity_id
= float_id
++;
172 Material::shininess_id
= float_id
;
174 BOOST_FOREACH(const Material
& mat
, vMaterials
)
176 OSG::UInt32 idx
= materialChunk
->addProperty();
178 materialChunk
->setVec3Property (idx
, Material:: ambient_id
, mat
.ambient
);
179 materialChunk
->setVec3Property (idx
, Material:: diffuse_id
, mat
.diffuse
);
180 materialChunk
->setVec3Property (idx
, Material:: specular_id
, mat
.specular
);
181 materialChunk
->setVec3Property (idx
, Material:: emissive_id
, mat
.emissive
);
183 materialChunk
->setFloatProperty(idx
, Material:: opacity_id
, mat
.opacity
);
184 materialChunk
->setFloatProperty(idx
, Material::shininess_id
, mat
.shininess
);
187 return OSG::MultiPropertySSBOChunkTransitPtr(materialChunk
);
190 void update_material_database_state(OSG::MultiPropertySSBOChunk
* materialChunk
, const VecMaterialsT
& vMaterials
)
194 if (materialChunk
->getNumProperties() != vMaterials
.size())
196 materialChunk
->clearProperties();
198 BOOST_FOREACH(const Material
& mat
, vMaterials
)
200 OSG::UInt32 idx
= materialChunk
->addProperty();
202 materialChunk
->setVec3Property (idx
, Material:: ambient_id
, mat
.ambient
);
203 materialChunk
->setVec3Property (idx
, Material:: diffuse_id
, mat
.diffuse
);
204 materialChunk
->setVec3Property (idx
, Material:: specular_id
, mat
.specular
);
205 materialChunk
->setVec3Property (idx
, Material:: emissive_id
, mat
.emissive
);
207 materialChunk
->setFloatProperty(idx
, Material:: opacity_id
, mat
.opacity
);
208 materialChunk
->setFloatProperty(idx
, Material::shininess_id
, mat
.shininess
);
213 for (OSG::UInt32 idx
= 0; idx
< vMaterials
.size(); ++idx
)
215 const Material
& mat
= vMaterials
[idx
];
217 materialChunk
->setVec3Property (idx
, Material:: ambient_id
, mat
.ambient
);
218 materialChunk
->setVec3Property (idx
, Material:: diffuse_id
, mat
.diffuse
);
219 materialChunk
->setVec3Property (idx
, Material:: specular_id
, mat
.specular
);
220 materialChunk
->setVec3Property (idx
, Material:: emissive_id
, mat
.emissive
);
222 materialChunk
->setFloatProperty(idx
, Material:: opacity_id
, mat
.opacity
);
223 materialChunk
->setFloatProperty(idx
, Material::shininess_id
, mat
.shininess
);
229 OSG::SimpleSceneManagerRefPtr mgr
= NULL
;
231 OSG::MultiPropertySSBOChunkRefPtr ssbo_data_state
= NULL
;
233 std::string
get_cp_program();
235 OSG::NodeTransitPtr
createPlane(OSG::TextureObjChunk
* texObjChunk
)
237 OSG::MaterialChunkRefPtr matChunk
= OSG::MaterialChunk::create();
238 matChunk
->setDiffuse(OSG::Color4f(0.f
, 0.f
, 0.f
, 1.f
));
240 OSG::TextureEnvChunkRefPtr texEnvChunk
= OSG::TextureEnvChunk::create();
241 texEnvChunk
->setEnvMode(GL_REPLACE
);
243 OSG::ChunkMaterialRefPtr chunkMaterial
= OSG::ChunkMaterial::create();
244 chunkMaterial
->addChunk(texObjChunk
, 0);
245 chunkMaterial
->addChunk(texEnvChunk
);
246 chunkMaterial
->addChunk(matChunk
);
249 OSG::MaterialGroupRefPtr matGroup
= OSG::MaterialGroup::create();
250 matGroup
->setMaterial(chunkMaterial
);
252 OSG::NodeRefPtr plane
= OSG::makeNodeFor(matGroup
);
254 OSG::GeometryRefPtr geometry
= OSG::Geometry::create();
255 geometry
->setDlistCache(false);
256 geometry
->setUseVAO(true);
257 geometry
->setUseAttribCalls(true);
259 OSG::NodeRefPtr geomNode
= OSG::makeNodeFor(geometry
);
261 OSG::GeoUInt8PropertyRefPtr types
= OSG::GeoUInt8Property ::create();
262 OSG::GeoUInt32PropertyRefPtr lengths
= OSG::GeoUInt32Property::create();
263 OSG::GeoPnt3fPropertyRefPtr vertices
= OSG::GeoPnt3fProperty ::create();
264 OSG::GeoVec3fPropertyRefPtr normals
= OSG::GeoVec3fProperty ::create();
265 OSG::GeoColor3fPropertyRefPtr colors
= OSG::GeoColor3fProperty::create();
266 OSG::GeoVec2fPropertyRefPtr textures
= OSG::GeoVec2fProperty ::create();
267 OSG::GeoUInt32PropertyRefPtr indices
= OSG::GeoUInt32Property::create();
269 types
->setUseVBO(true);
270 lengths
->setUseVBO(true);
271 indices
->setUseVBO(true);
272 vertices
->setUseVBO(true);
273 normals
->setUseVBO(true);
274 colors
->setUseVBO(true);
275 textures
->setUseVBO(true);
277 types
->setUsage(OSG::GeoProperty::UsageSystemSet
);
278 lengths
->setUsage(OSG::GeoProperty::UsageSystemSet
);
279 indices
->setUsage(OSG::GeoProperty::UsageSystemSet
);
280 vertices
->setUsage(OSG::GeoProperty::UsageSystemSet
);
281 normals
->setUsage(OSG::GeoProperty::UsageSystemSet
);
282 colors
->setUsage(OSG::GeoProperty::UsageSystemSet
);
283 textures
->setUsage(OSG::GeoProperty::UsageSystemSet
);
285 types
->push_back(4);
286 lengths
->push_back(6);
288 indices
->push_back(0);
289 indices
->push_back(1);
290 indices
->push_back(2);
291 indices
->push_back(0);
292 indices
->push_back(2);
293 indices
->push_back(3);
295 vertices
->push_back(OSG::Pnt3f(-1.f
,-1.f
,-1.f
));
296 vertices
->push_back(OSG::Pnt3f( 1.f
,-1.f
,-1.f
));
297 vertices
->push_back(OSG::Pnt3f( 1.f
, 1.f
,-3.f
));
298 vertices
->push_back(OSG::Pnt3f(-1.f
, 1.f
,-3.f
));
300 normals
->push_back(OSG::Vec3f(0.f
, 0.f
, 1.f
));
301 normals
->push_back(OSG::Vec3f(0.f
, 0.f
, 1.f
));
302 normals
->push_back(OSG::Vec3f(0.f
, 0.f
, 1.f
));
303 normals
->push_back(OSG::Vec3f(0.f
, 0.f
, 1.f
));
305 colors
->push_back(OSG::Color3f(0.f
, 1.f
, 0.f
));
307 textures
->push_back(OSG::Vec2i(0,0));
308 textures
->push_back(OSG::Vec2i(1,0));
309 textures
->push_back(OSG::Vec2i(1,1));
310 textures
->push_back(OSG::Vec2i(0,1));
312 geometry
->setTypes (types
);
313 geometry
->setLengths (lengths
);
314 geometry
->setIndices (indices
);
315 geometry
->setPositions(vertices
);
316 geometry
->setNormals (normals
);
317 geometry
->setColors (colors
);
318 geometry
->setTexCoords(textures
);
320 plane
->addChild(geomNode
);
322 return OSG::NodeTransitPtr(plane
);
325 OSG::NodeTransitPtr
createScene()
327 const OSG::UInt32 data_binding_point
= 5;
329 ssbo_data_state
= create_material_database_state(materials
);
331 OSG::ChunkMaterialRefPtr data_state
= OSG::ChunkMaterial::create();
332 data_state
->addChunk(ssbo_data_state
, data_binding_point
);
334 OSG::ImageRefPtr image
= OSG::ImageFileHandler::the()->read("Examples/CSM/Models/Textures/Earth512.png");
336 OSG::TextureObjChunkRefPtr texObjChunk
= OSG::TextureObjChunk::create();
337 texObjChunk
->setInternalFormat(GL_RGBA32F
);
338 texObjChunk
->setMinFilter(GL_LINEAR
);
339 texObjChunk
->setMagFilter(GL_LINEAR
);
340 texObjChunk
->setImage(image
);
342 OSG::NodeRefPtr planeNode
= createPlane(texObjChunk
);
344 OSG::AlgorithmComputeElementRefPtr algoCompElement
= OSG::AlgorithmComputeElement::create();
345 OSG::NodeRefPtr computeNode
= OSG::makeNodeFor(algoCompElement
);
346 computeNode
->addChild(planeNode
);
348 OSG::ComputeShaderAlgorithmRefPtr compShaderAlgo
= OSG::ComputeShaderAlgorithm::create();
349 algoCompElement
->setAlgorithm(compShaderAlgo
);
351 OSG::TextureImageChunkRefPtr texImgChunk
= OSG::TextureImageChunk::create();
352 texImgChunk
->setTexture(texObjChunk
);
353 texImgChunk
->setAccess(GL_WRITE_ONLY
);
354 texImgChunk
->setFormat(GL_RGBA32F
);
356 data_state
->addChunk(texImgChunk
, 0);
358 OSG::ShaderProgramRefPtr compShader
= OSG::ShaderProgram::create();
359 compShader
->setShaderType(GL_COMPUTE_SHADER
);
360 compShader
->setProgram(get_cp_program());
361 compShader
->addUniformVariable("destTex", 0);
362 compShader
->addUniformVariable("roll", 0.f
);
363 compShader
->addShaderStorageBlock("Materials", data_binding_point
); // block binding point
365 OSG::ComputeShaderChunkRefPtr compShaderChunk
= OSG::ComputeShaderChunk::create();
366 compShaderChunk
->addComputeShader(compShader
);
367 compShaderChunk
->setVariables(compShader
->getVariables());
369 compShaderAlgo
->setUseMemoryBarrier(true);
370 compShaderAlgo
->setUseVariableWorkGroupSize(true);
371 compShaderAlgo
->setMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT
);
372 compShaderAlgo
->setComputeShader(compShaderChunk
);
373 compShaderAlgo
->setDispatchConfig(work_group_count
);
374 compShaderAlgo
->setWorkGroupSize(work_group_size
);
375 compShaderAlgo
->setChunkMaterial(data_state
);
377 OSG::NodeRefPtr scene
= OSG::makeCoredNode
<OSG::Group
>();
378 scene
->addChild(computeNode
);
380 OSG::TimeSensorRefPtr sceneTimer
= OSG::TimeSensor::create();
381 sceneTimer
->setLoop(true);
382 sceneTimer
->setCycleInterval(10);
384 OSG::VRMLScalarInterpolatorRefPtr rollInter
= OSG::VRMLScalarInterpolator::create();
385 rollInter
->editMFKeyValue()->push_back(0.f
);
386 rollInter
->editMFKeyValue()->push_back(10.24f
);
388 rollInter
->editMFKey()->push_back(0.f
);
389 rollInter
->editMFKey()->push_back(1.f
);
391 const OSG::ShaderVariableReal
* varRealRoll
= dynamic_cast<const OSG::ShaderVariableReal
*>(compShader
->getVariables()->getVariable("roll"));
393 addConnection(sceneTimer
, "fraction", rollInter
, "inValue");
394 addConnection(rollInter
, "outValue", const_cast<OSG::ShaderVariableReal
*>(varRealRoll
), "value");
396 OSG::ContainerCollectionRefPtr containerCollection
= OSG::ContainerCollection::create();
398 containerCollection
->addContainer(rollInter
);
399 containerCollection
->addContainer(sceneTimer
);
401 scene
->addAttachment(containerCollection
);
403 return OSG::NodeTransitPtr(scene
);
407 // forward declaration so we can have the interesting stuff upfront
409 int setupGLUT(int *argc
, char *argv
[]);
414 // Initialize GLUT & OpenSG and set up the scene
416 int main(int argc
, char **argv
)
418 OSG::preloadSharedObject("OSGImageFileIO");
421 OSG::osgInit(argc
,argv
);
424 int winid
= setupGLUT(&argc
, argv
);
428 // open a new scope, because the pointers below should go out of scope
429 // before entering glutMainLoop.
430 // Otherwise OpenSG will complain about objects being alive after shutdown.
432 // the connection between GLUT and OpenSG
433 OSG::GLUTWindowRefPtr gwin
= OSG::GLUTWindow::create();
434 gwin
->setGlutId(winid
);
437 // create the SimpleSceneManager helper
438 mgr
= OSG::SimpleSceneManager::create();
439 mgr
->setWindow(gwin
);
442 OSG::NodeRefPtr scene
= createScene();
446 OSG::commitChanges();
448 // show the whole scene
459 // GLUT callback functions
467 OSG::FrameHandler::the()->frame();
469 OSG::commitChanges();
474 // react to size changes
476 void reshape(int w
, int h
)
483 // react to mouse button presses
485 void mouse(int button
, int state
, int x
, int y
)
488 mgr
->mouseButtonRelease(button
, x
, y
);
490 mgr
->mouseButtonPress(button
, x
, y
);
496 // react to mouse motions with pressed buttons
498 void motion(int x
, int y
)
500 mgr
->mouseMove(x
, y
);
507 void keyboard(unsigned char k
, int x
, int y
)
513 // clean up global variables
515 ssbo_data_state
= NULL
;
526 materials
= initialize_materials(num_materials
);
527 update_material_database_state(ssbo_data_state
, materials
);
535 // setup the GLUT library which handles the windows for us
537 int setupGLUT(int *argc
, char *argv
[])
539 glutInit(argc
, argv
);
540 glutInitDisplayMode(GLUT_RGB
| GLUT_DEPTH
| GLUT_DOUBLE
);
541 glutInitWindowSize(1000, 800);
543 int winid
= glutCreateWindow("OpenSG");
545 glutReshapeFunc(reshape
);
546 glutDisplayFunc(display
);
547 glutMouseFunc(mouse
);
548 glutMotionFunc(motion
);
549 glutKeyboardFunc(keyboard
);
551 // call the redraw function whenever there's nothing else to do
552 glutIdleFunc(display
);
559 glutReshapeFunc(NULL
);
560 glutDisplayFunc(NULL
);
562 glutMotionFunc(NULL
);
563 glutKeyboardFunc(NULL
);
569 std::cout
<< "Esc : quit example" << std::endl
;
570 std::cout
<< "m : reinitialize material database" << std::endl
;
573 std::string
get_cp_program()
579 ost
<< "#version 450 compatibility"
581 << endl
<< "#extension GL_ARB_compute_variable_group_size: enable"
583 << endl
<< "uniform float roll;"
584 << endl
<< "uniform writeonly image2D destTex;"
586 << endl
<< "struct Material"
588 << endl
<< " vec3 ambient;"
589 << endl
<< " vec3 diffuse;"
590 << endl
<< " vec3 specular;"
591 << endl
<< " vec3 emissive;"
593 << endl
<< " float opacity;"
594 << endl
<< " float shininess;"
597 << endl
<< "layout (std430) buffer Materials"
599 << endl
<< " Material material[];"
600 << endl
<< "} materials;"
602 << endl
<< "layout (local_size_variable) in;"
604 << endl
<< "void main()"
607 << endl
<< " // Due to driver issue at the time of writing this code: The build in variable"
608 << endl
<< " // gl_LocalInvocationIndex is not properly set in case of a variable work group"
609 << endl
<< " // size specification."
611 //<< endl << " uint localInvocationIndex = gl_LocalInvocationIndex;"
612 << endl
<< " uint localInvocationIndex = gl_LocalInvocationID.z * (gl_LocalGroupSizeARB.x * gl_LocalGroupSizeARB.y)"
613 << endl
<< " + gl_LocalInvocationID.y * gl_LocalGroupSizeARB.x"
614 << endl
<< " + gl_LocalInvocationID.x;"
617 << endl
<< " ivec2 storePos = ivec2( gl_GlobalInvocationID.xy );"
618 << endl
<< " float localCoef = length( vec2( ivec2(gl_LocalInvocationID.xy) - 8 ) / 8.0 );"
619 << endl
<< " float globalCoef = sin( float(gl_WorkGroupID.x + gl_WorkGroupID.y) * 0.1 + roll ) * 0.5;"
621 << endl
<< " vec4 color = vec4(materials.material[localInvocationIndex].diffuse, 0.0);"
623 << endl
<< " color.x -= globalCoef * localCoef;"
624 << endl
<< " color.y -= globalCoef * localCoef;"
625 << endl
<< " color.z -= globalCoef * localCoef;"
627 << endl
<< " imageStore(destTex, storePos, color);"