1 // OpenSG Tutorial Example: FBO Texture
3 // This example shows how to use FrameBufferObject and SimpleStage to render
4 // a subtree of the scene graph to a texture and then use that texture
5 // when drawing another part of the scene.
7 // The scene graph constructed in this example looks like this:
9 // scene[Group] -+- fboScene[SimpleStage] --- fboScene --- {loaded model +
10 // | light and beacon}
12 // +- flagScene[Group] --- {flag and pole}
14 // If you run this example and zoom in close to the flag or move it to the
15 // edge of the screen the model on it may stop rotating. This happens because
16 // the model actually is positioned about half way up the flag's pole and
17 // get's frustum culled if that part of the scene is outside the camera
20 #ifdef OSG_BUILD_ACTIVE
23 #include <OSGConfig.h>
24 #include <OSGSimpleGeometry.h>
25 #include <OSGGLUTWindow.h>
26 #include <OSGSimpleSceneManager.h>
27 #include <OSGBaseFunctions.h>
28 #include <OSGTransform.h>
29 #include <OSGComponentTransform.h>
31 #include <OSGSimpleStage.h>
32 #include <OSGPointLight.h>
33 #include <OSGFrameBufferObject.h>
34 #include <OSGTextureBuffer.h>
35 #include <OSGRenderBuffer.h>
36 #include <OSGTextureObjChunk.h>
37 #include <OSGTextureEnvChunk.h>
38 #include <OSGTexGenChunk.h>
39 #include <OSGTwoSidedLightingChunk.h>
40 #include <OSGSceneFileHandler.h>
41 #include <OSGImageFunctions.h>
42 #include <OSGSimpleTexturedMaterial.h>
43 #include <OSGTextureTransformChunk.h>
44 #include <OSGGradientBackground.h>
45 #include <OSGPerspectiveCamera.h>
48 #include <OpenSG/OSGGLUT.h>
49 #include <OpenSG/OSGConfig.h>
50 #include <OpenSG/OSGSimpleGeometry.h>
51 #include <OpenSG/OSGGLUTWindow.h>
52 #include <OpenSG/OSGSimpleSceneManager.h>
53 #include <OpenSG/OSGBaseFunctions.h>
54 #include <OpenSG/OSGTransform.h>
55 #include <OpenSG/OSGComponentTransform.h>
57 #include <OpenSG/OSGSimpleStage.h>
58 #include <OpenSG/OSGPointLight.h>
59 #include <OpenSG/OSGFrameBufferObject.h>
60 #include <OpenSG/OSGTextureBuffer.h>
61 #include <OpenSG/OSGRenderBuffer.h>
62 #include <OpenSG/OSGTextureObjChunk.h>
63 #include <OpenSG/OSGTextureEnvChunk.h>
64 #include <OpenSG/OSGTexGenChunk.h>
65 #include <OpenSG/OSGTwoSidedLightingChunk.h>
66 #include <OpenSG/OSGSceneFileHandler.h>
67 #include <OpenSG/OSGImageFunctions.h>
68 #include <OpenSG/OSGSimpleTexturedMaterial.h>
69 #include <OpenSG/OSGTextureTransformChunk.h>
70 #include <OpenSG/OSGGradientBackground.h>
71 #include <OpenSG/OSGPerspectiveCamera.h>
75 const OSG::Real32 flagHeight
= 8.0f
;
76 const OSG::Real32 flagWidth
= 16.0f
;
77 const OSG::UInt32 flagGeoHor
= static_cast<OSG::UInt32
>(flagWidth
* 3);
78 const OSG::UInt32 flagGeoVert
= static_cast<OSG::UInt32
>(flagHeight
/ 2);
79 const OSG::Real32 flagWaveDamp
= 0.06f
;
81 const OSG::Real32 poleHeight
= 24.0f
;
82 const OSG::Real32 poleDia
= poleHeight
* 0.01f
;
84 // fbo size -- you can increase these values to get a higher resolution image
85 const OSG::UInt32 fboWidth
= static_cast<OSG::UInt32
>(flagWidth
* 32);
86 const OSG::UInt32 fboHeight
= static_cast<OSG::UInt32
>(flagHeight
* 32);
89 OSG::SimpleSceneManagerRefPtr mgr
;
90 OSG::NodeRefPtr stageCamBeaconN
;
91 OSG::TransformRefPtr stageCamBeacon
;
93 OSG::NodeRefPtr modelTransN
;
94 OSG::TransformRefPtr modelTrans
;
96 // forward declaration so we can have the interesting stuff upfront
97 int setupGLUT (int *argc
, char *argv
[]);
98 OSG::NodeTransitPtr
buildFBOScene(int argc
, char *argv
[]);
99 OSG::NodeTransitPtr
buildScene (OSG::TextureObjChunkRefPtr fboTex
);
102 Construct a scene that uses a Stage to render a subtree to an FBO (making
103 the result available as a texture) and use that in another subtree.
105 OSG::NodeTransitPtr
buildStage(int argc
, char *argv
[])
108 Begin by setting up an FBO with a TextureBuffer, so we can capture
109 and reuse what is being rendered to the FBO.
112 OSG::ImageRefPtr fboTexImg
= OSG::Image ::create();
113 OSG::TextureObjChunkRefPtr fboTex
= OSG::TextureObjChunk ::create();
115 OSG::FrameBufferObjectRefPtr fbo
= OSG::FrameBufferObject::create();
116 OSG::TextureBufferRefPtr texBuf
= OSG::TextureBuffer ::create();
117 OSG::RenderBufferRefPtr depthBuf
= OSG::RenderBuffer ::create();
119 // set up the texture ...
120 fboTexImg
->set(OSG::Image::OSG_RGB_PF
, fboWidth
, fboHeight
);
121 fboTex
->setImage(fboTexImg
);
123 // ... and add it to the texture buffer
124 texBuf
->setTexture(fboTex
);
126 // add a depth attachment, otherwise there is no depth buffer when
127 // rendering to the FBO
128 depthBuf
->setInternalFormat(GL_DEPTH_COMPONENT24
);
130 // make the fbo render to the texture
131 fbo
->setColorAttachment(texBuf
, 0);
132 fbo
->setDepthAttachment(depthBuf
);
133 fbo
->editMFDrawBuffers()->push_back(GL_COLOR_ATTACHMENT0_EXT
);
134 fbo
->setWidth (fboWidth
);
135 fbo
->setHeight(fboHeight
);
138 enable post processing for the FBO, this generates mip maps for the
139 texture if a mip map filter is active (the default for minFilter is
140 GL_LINEAR_MIPMAP_LINEAR).
141 Alternatively, one could set the texture filter to one that does not
142 require mip maps, e.g. call fboTex->setMinFilter(GL_LINEAR);
144 fbo
->setPostProcessOnDeactivate(true);
147 Next we set up a Stage, which renders the subtree below it to its
148 render target (the FBO from above).
151 OSG::SimpleStageRefPtr stage
= OSG::SimpleStage::create();
152 OSG::NodeRefPtr stageN
= OSG::makeNodeFor(stage
);
154 // add the scene to be rendered to the fbo as child of the Stage
155 OSG::NodeRefPtr fboSceneN
= buildFBOScene(argc
, argv
);
156 stageN
->addChild(fboSceneN
);
158 // make the stage render to the FBO instead of the normal framebuffer
159 stage
->setRenderTarget(fbo
);
161 // use the full size of the target (this is like setting up the viewport
163 stage
->setSize(0.0f
, 0.0f
, 1.0f
, 1.0f
);
165 // set a different background for things on the stage ...
166 OSG::GradientBackgroundRefPtr gb
= OSG::GradientBackground::create();
167 gb
->addLine(OSG::Color3f(0.3f
, 0.3f
, 0.8f
), 0.0f
);
168 gb
->addLine(OSG::Color3f(0.5f
, 0.5f
, 0.5f
), 1.0f
);
169 stage
->setBackground(gb
);
171 // ... and add a camera
172 OSG::PerspectiveCameraRefPtr stageCam
= OSG::PerspectiveCamera::create();
173 stage
->setCamera(stageCam
);
175 stageCam
->setBeacon(stageCamBeaconN
);
176 stageCam
->setNear ( 0.1f
);
177 stageCam
->setFar (1000.0);
178 stageCam
->setFov ( 1.5);
180 // add the scene using the fbo
181 OSG::NodeRefPtr sceneN
= buildScene(fboTex
);
183 // place the stage and the scene using the fbo under a common group
184 OSG::NodeRefPtr rootN
= OSG::makeCoredNode
<OSG::Group
>();
186 rootN
->addChild(stageN
);
187 rootN
->addChild(sceneN
);
189 return OSG::NodeTransitPtr(rootN
);
193 // Initialize GLUT & OpenSG and set up the scene
194 int main(int argc
, char **argv
)
197 OSG::osgInit(argc
,argv
);
200 int winid
= setupGLUT(&argc
, argv
);
202 // open a new scope, because the pointers below should go out of scope
203 // before entering glutMainLoop.
204 // Otherwise OpenSG will complain about objects being alive after shutdown.
206 // the connection between GLUT and OpenSG
207 OSG::GLUTWindowRefPtr gwin
= OSG::GLUTWindow::create();
208 gwin
->setGlutId(winid
);
211 OSG::NodeRefPtr scene
= buildStage(argc
, argv
);
213 OSG::commitChanges();
215 // create the SimpleSceneManager helper
216 mgr
= OSG::SimpleSceneManager::create();
218 // tell the manager what to manage
219 mgr
->setWindow(gwin
);
220 mgr
->setRoot (scene
);
222 // show the whole scene
233 // GLUT callback functions
236 // react to size changes
237 void reshape(int w
, int h
)
243 // react to mouse button presses
244 void mouse(int button
, int state
, int x
, int y
)
247 mgr
->mouseButtonRelease(button
, x
, y
);
249 mgr
->mouseButtonPress(button
, x
, y
);
254 // react to mouse motions with pressed buttons
255 void motion(int x
, int y
)
257 mgr
->mouseMove(x
, y
);
269 static OSG::Real64 t0
= OSG::getSystemTime();
271 // get the current time
272 OSG::Real64 t
= OSG::getSystemTime() - t0
;
276 q
.setValueAsAxisDeg(0, 1, 0, t
* 10.f
);
278 modelTrans
->setMatrix(m
);
281 OSG::commitChangesAndClear();
287 void keyboard(unsigned char k
, int , int )
293 // clean up global variables
295 stageCamBeaconN
= NULL
;
296 stageCamBeacon
= NULL
;
308 // setup the GLUT library which handles the windows for us
309 int setupGLUT(int *argc
, char *argv
[])
311 glutInit(argc
, argv
);
312 glutInitDisplayMode(GLUT_RGB
| GLUT_DEPTH
| GLUT_DOUBLE
);
314 int winid
= glutCreateWindow("OpenSG");
316 glutReshapeFunc(reshape
);
317 glutDisplayFunc(display
);
318 glutMouseFunc(mouse
);
319 glutMotionFunc(motion
);
320 glutKeyboardFunc(keyboard
);
322 // call the redraw function whenever there's nothing else to do
323 glutIdleFunc(update
);
329 Loads a model given on the command line or creates a fallback.
330 This scene is rendered to a texture (fboTexture) which is later used on
331 another object, however none of this happens in here, only the scene is
334 OSG::NodeTransitPtr
buildFBOScene(int argc
, char *argv
[])
336 OSG::NodeRefPtr modelN
;
339 modelN
= OSG::SceneFileHandler::the()->read(argv
[1]);
341 // no argument or loading failed -> use a torus
343 modelN
= OSG::makeTorus(0.3f
, 4, 16, 64);
345 OSG::commitChanges();
346 OSG::Pnt3f bbMin
, bbMax
;
347 modelN
->updateVolume();
348 modelN
->getVolume().getBounds(bbMin
, bbMax
);
350 OSG::NodeRefPtr fboSceneN
= OSG::makeCoredNode
<OSG::Group
>();
352 stageCamBeaconN
= OSG::makeCoredNode
<OSG::Transform
>(&stageCamBeacon
);
354 modelTransN
= OSG::makeCoredNode
<OSG::Transform
>(&modelTrans
);
356 // move the camera back
357 OSG::Real32 bbDia
= (bbMax
- bbMin
).length();
358 stageCamBeacon
->editMatrix().setTranslate(OSG::Vec3f(0.0f
, 0.0f
, bbDia
));
360 OSG::PointLightRefPtr light
;
361 OSG::NodeRefPtr lightN
= OSG::makeCoredNode
<OSG::PointLight
>(&light
);
362 light
->setBeacon(stageCamBeaconN
);
364 fboSceneN
->addChild(lightN
);
365 fboSceneN
->addChild(stageCamBeaconN
);
367 lightN
->addChild(modelTransN
);
369 modelTransN
->addChild(modelN
);
371 return OSG::NodeTransitPtr(fboSceneN
);
374 // create a wood texture
375 OSG::SimpleTexturedMaterialTransitPtr
createWoodMaterial(void)
377 OSG::SimpleTexturedMaterialRefPtr mat
=
378 OSG::SimpleTexturedMaterial::create();
380 OSG::ImageRefPtr img
= OSG::Image::create();
381 createNoise(img
, OSG::Image::OSG_L_PF
, 7, 64);
384 mat
->setEnvMode(GL_MODULATE
);
385 mat
->setDiffuse(OSG::Color3f(0.9f
, 0.57f
, 0.1f
));
386 mat
->setSpecular(OSG::Color3f(0.2f
, 0.2f
, 0.1f
));
388 OSG::TextureTransformChunkRefPtr ttrans
=
389 OSG::TextureTransformChunk::create();
391 m
.setScale(2.0, 8.0, 2.0);
392 ttrans
->setMatrix(m
);
394 mat
->addChunk(ttrans
);
396 return OSG::SimpleTexturedMaterialTransitPtr(mat
);
401 Builds a scene with a flag on a pole. The flag is textured with the
402 image of the fbo scene (fboTexture).
404 OSG::NodeTransitPtr
buildScene(OSG::TextureObjChunkRefPtr fboTex
)
406 OSG::NodeRefPtr flagScene
= OSG::makeCoredNode
<OSG::Group
>();
407 OSG::GeometryRefPtr flagGeo
= OSG::makePlaneGeo(flagWidth
, flagHeight
,
408 flagGeoHor
, flagGeoVert
);
410 // disable caching as we will change this geometry every frame
411 flagGeo
->setDlistCache(false);
413 OSG::SimpleMaterialRefPtr flagMat
= OSG::SimpleMaterial ::create();
414 OSG::TextureEnvChunkRefPtr fboTexEnv
= OSG::TextureEnvChunk::create();
416 fboTexEnv
->setEnvMode(GL_REPLACE
);
418 flagMat
->addChunk(fboTex
);
419 flagMat
->addChunk(fboTexEnv
);
421 // add a light glossy effect (environment noise-map)
424 OSG::ImageRefPtr noise
= OSG::Image::create();
425 createNoise(noise
, OSG::Image::OSG_I_PF
, 5, 256);
427 // make noise image darker (as it will be GL_ADDed)
428 for(OSG::UInt32 i
= 0; i
< noise
->getSize(); ++i
)
429 noise
->editData()[i
] >>= 2; // *= 0.125
431 OSG::TextureObjChunkRefPtr glossObj
= OSG::TextureObjChunk::create();
432 OSG::TextureEnvChunkRefPtr glossEnv
= OSG::TextureEnvChunk::create();
434 glossObj
->setImage(noise
);
435 glossEnv
->setEnvMode(GL_ADD
);
437 OSG::TexGenChunkRefPtr envMap
= OSG::TexGenChunk::create();
438 envMap
->setGenFuncS(GL_SPHERE_MAP
);
439 envMap
->setGenFuncT(GL_SPHERE_MAP
);
441 // add for use with 2nd texture unit
442 flagMat
->addChunk(glossObj
, 1);
443 flagMat
->addChunk(glossEnv
, 1);
444 flagMat
->addChunk(envMap
, 1);
448 OSG::StateChunkRefPtr(OSG::TwoSidedLightingChunk::create()));
449 flagMat
->setSpecular(OSG::Color3f(0.4f
, 0.4f
, 0.4f
));
450 flagMat
->setDiffuse (OSG::Color3f(0.7f
, 0.7f
, 0.7f
));
452 flagGeo
->setMaterial(flagMat
);
454 // create transform node to hook up the flag to the pole
455 OSG::ComponentTransformRefPtr flagTrans
;
456 OSG::NodeRefPtr flagTransN
=
457 OSG::makeCoredNode
<OSG::ComponentTransform
>(&flagTrans
);
459 OSG::Vec3f
v(0.5f
* flagWidth
, 0.5f
* (poleHeight
- flagHeight
) , 0.0f
);
460 flagTrans
->setTranslation(v
);
462 // attach flag-geometry to transform-node
463 flagTransN
->addChild(OSG::NodeRefPtr(OSG::makeNodeFor(flagGeo
)));
466 OSG::GeometryRefPtr pole
= OSG::makeCylinderGeo(poleHeight
, poleDia
, 24, true, true, true);
467 OSG::NodeRefPtr poleN
= OSG::makeNodeFor(pole
);
468 OSG::MaterialRefPtr woodMat
= createWoodMaterial();
470 pole
->setMaterial(woodMat
);
472 // attach objects to group node
473 flagScene
->addChild(flagTransN
);
474 flagScene
->addChild(poleN
);
476 return OSG::NodeTransitPtr(flagScene
);