1 // OpenSG Tutorial Example: Lights
3 // This example shows how to create and manipulate light sources
6 #ifdef OSG_BUILD_ACTIVE
10 #include <OSGSimpleGeometry.h>
11 #include <OSGGLUTWindow.h>
12 #include <OSGSimpleSceneManager.h>
13 #include <OSGTransform.h>
16 // new header: the light sources
17 #include <OSGDirectionalLight.h>
18 #include <OSGPointLight.h>
19 #include <OSGSpotLight.h>
22 #include <OpenSG/OSGGLUT.h>
23 #include <OpenSG/OSGConfig.h>
24 #include <OpenSG/OSGSimpleGeometry.h>
25 #include <OpenSG/OSGGLUTWindow.h>
26 #include <OpenSG/OSGSimpleSceneManager.h>
27 #include <OpenSG/OSGTransform.h>
28 #include <OpenSG/OSGGroup.h>
30 // new header: the light sources
31 #include <OpenSG/OSGDirectionalLight.h>
32 #include <OpenSG/OSGPointLight.h>
33 #include <OpenSG/OSGSpotLight.h>
36 OSG::UInt32 nlights
= 6;
38 OSG::TransformRefPtr lightBeacons
[8];
39 OSG::LightRefPtr lights
[8];
41 // The SimpleSceneManager to manage simple applications
42 OSG::SimpleSceneManagerRefPtr mgr
;
44 // forward declaration so we can have the interesting stuff upfront
45 int setupGLUT( int *argc
, char *argv
[] );
47 // create the motion matrix for a light source at time t
48 void makeMatrix(OSG::Real32 t
, OSG::Matrix
&result
)
52 result
.setTransform(OSG::Quaternion(OSG::Vec3f(0,0,1), -OSG::Pi
/ 2));
54 m
.setTransform(OSG::Vec3f(1, 0, 0));
57 m
.setTransform(OSG::Quaternion(OSG::Vec3f(0,1,0), t
/ 1000.f
));
60 m
.setTransform(OSG::Vec3f(2, 0, 0));
63 m
.setTransform(OSG::Quaternion(OSG::Vec3f(0,0,1), t
/ 3000.f
));
71 OSG::Real32 t
= glutGet(GLUT_ELAPSED_TIME
);
73 // stagger the lights in time, so that they follow each other
74 for(OSG::UInt16 i
= 0; i
< nlights
; ++i
)
78 makeMatrix(t
- 2000 * i
, m
);
80 lightBeacons
[i
]->setMatrix(m
);
87 // Initialize GLUT & OpenSG and set up the scene
88 int main(int argc
, char **argv
)
91 OSG::osgInit(argc
,argv
);
94 int winid
= setupGLUT(&argc
, argv
);
99 if(sscanf(argv
[1], "%u", &nlights
) != 1)
101 FWARNING(("Number of lights '%s' not understood.\n", argv
[1]));
106 // open a new scope, because the pointers below should go out of scope
107 // before entering glutMainLoop.
108 // Otherwise OpenSG will complain about objects being alive after shutdown.
111 // the connection between GLUT and OpenSG
112 OSG::GLUTWindowRefPtr gwin
= OSG::GLUTWindow::create();
113 gwin
->setGlutId(winid
);
117 A Light defines a source of light in the scene. Generally, two types
118 of information are of interest: The position of the light source
119 (geometry), and what elements of the scene are lit (semantics).
121 Using the position of the light in the graph for geometry allows
122 moving the Light just like any other node, by putting it below a
123 OSG::Transform Node and changing the transformation. This consistency
124 also simplifies attaching Lights to moving parts in the scene: just
125 put them below the same Transform and they will move with the object.
127 The semantic interpretation also makes sense, it lets you restrict the
128 influence area of the light to a subgraph of the scene. This can be
129 used for efficiency, as every active light increases the amount of
130 calculations necessary per vertex, even if the light doesn't influence
131 the vertex, because it is too far away. It can also be used to
132 overcome the restrictions on the number of lights. OpenSG currently
133 only allows 8 concurrently active lights.
135 It is also not difficult to imagine situations where both
136 interpretations are necessary at the same time. Take for example a car
137 driving through a night scene. You'd want to headlights to be fixed to
138 the car and move together with it. But at the same time they should
139 light the houses you're driving by, and not the mountains in the
142 Thus there should be a way to do both at the same time. OpenSG solves
143 this by splitting the two tasks to two Nodes. The Light's Node is for
144 the sematntic part, it defines which object are lit by the Light. FOr
145 the geometrc part the Light keeps a SFNodePtr to a different Node, the
146 so called beacon. The local coordinate system of the beacon provides
147 the reference coordinate system for the light's position.
150 Thus the typical setup of an OpenSG scenegraph starts with a set of
151 lights, which light the whole scene, followed by the actual geometry.
153 Tip: Using the beacon of the camera (see \ref PageSystemWindowCamera)
154 as the beacon of a light source creates a headlight.
157 Every light is closely related to OpenGL's light specification. It has
158 a diffuse, specular and ambient color. Additionally it can be switched
159 on and off using the on field.
165 OSG::NodeRefPtr scene
= OSG::Node::create();
166 OSG::GroupRefPtr group
= OSG::Group::create();
167 scene
->setCore(group
);
169 // create the scene to be lit
171 // a simple torus is fine for now.
172 // You can add more Geometry here if you want to.
173 OSG::NodeRefPtr lit_scene
= OSG::makeTorus(.5, 2, 32, 64);
175 // helper node to keep the lights on top of each other
176 OSG::NodeRefPtr lastnode
= lit_scene
;
178 // create the light sources
179 OSG::Color3f colors
[] =
181 OSG::Color3f(1,0,0), OSG::Color3f(0,1,0), OSG::Color3f(0,0,1),
182 OSG::Color3f(1,1,0), OSG::Color3f(0,1,1), OSG::Color3f(1,0,1),
183 OSG::Color3f(1,1,1), OSG::Color3f(1,1,1)
187 FWARNING(("Currently only 8 lights supported\n"));
191 // scale the lights to not overexpose everything. Just a little.
192 OSG::Real32 scale
= OSG::osgMax(1., 1.5 / nlights
);
194 for(OSG::UInt16 i
= 0; i
< nlights
; ++i
)
196 // create the light source
197 OSG::NodeRefPtr light
= OSG::Node::create();
198 OSG::LightRefPtr light_core
;
199 OSG::NodeRefPtr geo_node
;
204 The PointLight has a position to define its location. In
205 addition, as it really is located in the scene, it has
206 attenuation parameters to change the light's intensity
207 depending on the distance to the light.
209 Point lights are more expesinve to compute than directional
210 lights, but not quite as expesive as spot lights. If you need
211 to see the localized effects of the light, a point light is a
212 good compromise between speed and quality.
216 OSG::PointLightRefPtr l
= OSG::PointLight::create();
218 l
->setPosition (0, 0, 0);
219 l
->setConstantAttenuation (1);
220 l
->setLinearAttenuation (0);
221 l
->setQuadraticAttenuation (3);
223 // a little sphere to show where the light is
224 geo_node
= OSG::makeLatLongSphere(8, 8, 0.1f
);
226 OSG::GeometryRefPtr geo
=
227 dynamic_cast<OSG::Geometry
*>(geo_node
->getCore());
228 OSG::SimpleMaterialRefPtr sm
=
229 OSG::SimpleMaterial::create();
232 sm
->setDiffuse(OSG::Color3f( colors
[i
][0],
236 geo
->setMaterial(sm
);
244 The DirectionalLight just has a direction.
246 To use it as a headlight use (0,0,-1) as a direction. it is
247 the computationally cheapest light source. Thus for the
248 fastest lit rendering, just a single directional light source.
249 The osg::SimpleSceneManager's headlight is a directional light
255 OSG::DirectionalLightRefPtr l
=
256 OSG::DirectionalLight::create();
258 l
->setDirection(0, 0, 1);
260 // a little cylinder to show where the light is
261 geo_node
= OSG::makeCylinder(.1f
, .03f
, 8, true, true, true);
263 OSG::GeometryRefPtr geo
=
264 dynamic_cast<OSG::Geometry
*>(geo_node
->getCore());
265 OSG::SimpleMaterialRefPtr sm
=
266 OSG::SimpleMaterial::create();
269 sm
->setDiffuse(OSG::Color3f( colors
[i
][0],
273 geo
->setMaterial(sm
);
280 The SpotLight adds a direction to the PointLight and a
281 spotCutOff angle to define the area that's lit. To define the
282 light intensity fallof within that area the spotExponent field
285 Spot lights are very expensive to compute, use them sparingly.
289 OSG::SpotLightRefPtr l
= OSG::SpotLight::create();
291 l
->setPosition (OSG::Pnt3f(0, 0, 0));
292 l
->setDirection (OSG::Vec3f(0, -1, 0));
293 l
->setSpotExponent (2);
294 l
->setSpotCutOff (OSG::osgDegree2Rad(45));
295 l
->setConstantAttenuation (1);
296 l
->setLinearAttenuation (0);
297 l
->setQuadraticAttenuation (3);
299 // a little cone to show where the light is
300 geo_node
= OSG::makeCone(.2f
, .2f
, 8, true, true);
302 OSG::GeometryRefPtr geo
=
303 dynamic_cast<OSG::Geometry
*>(geo_node
->getCore());
304 OSG::SimpleMaterialRefPtr sm
=
305 OSG::SimpleMaterial::create();
308 sm
->setDiffuse(OSG::Color3f( colors
[i
][0],
312 geo
->setMaterial(sm
);
319 // create the beacon and attach it to the scene
320 OSG::NodeRefPtr beacon
= OSG::Node::create();
321 OSG::TransformRefPtr beacon_core
= OSG::Transform::create();
323 lightBeacons
[i
] = beacon_core
;
325 beacon
->setCore(beacon_core
);
326 beacon
->addChild(geo_node
);
328 scene
->addChild(beacon
);
330 light_core
->setAmbient (colors
[i
][0] / scale
,
331 colors
[i
][1] / scale
,
332 colors
[i
][2] / scale
,
334 light_core
->setDiffuse (colors
[i
][0] / scale
,
335 colors
[i
][1] / scale
,
336 colors
[i
][2] / scale
,
338 light_core
->setSpecular(1 / scale
,
342 light_core
->setBeacon (beacon
);
344 light
->setCore(light_core
);
345 light
->addChild(lastnode
);
347 lights
[i
] = light_core
;
351 scene
->addChild(lastnode
);
353 OSG::commitChanges();
355 // create the SimpleSceneManager helper
356 mgr
= OSG::SimpleSceneManager::create();
358 // tell the manager what to manage
359 mgr
->setWindow(gwin
);
360 mgr
->setRoot (scene
);
362 // switch the headlight off, we have enough lights as is
363 mgr
->setHeadlight(false);
365 // show the whole scene
376 // GLUT callback functions
379 // react to size changes
380 void reshape(int w
, int h
)
386 // react to mouse button presses
387 void mouse(int button
, int state
, int x
, int y
)
390 mgr
->mouseButtonRelease(button
, x
, y
);
392 mgr
->mouseButtonPress(button
, x
, y
);
397 // react to mouse motions with pressed buttons
398 void motion(int x
, int y
)
400 mgr
->mouseMove(x
, y
);
405 void keyboard(unsigned char k
, int x
, int y
)
411 // clean up global variables
419 case 'a': // activate all lights
421 for(OSG::UInt16 i
= 0; i
< nlights
; ++i
)
423 lights
[i
]->setOn(true);
428 case 's': // deactivate all but the spot lights
430 for(OSG::UInt16 i
= 0; i
< nlights
; ++i
)
432 if(lights
[i
]->getTypeId() != OSG::SpotLight::getClassTypeId())
434 lights
[i
]->setOn(false);
438 lights
[i
]->setOn(true);
441 OSG::commitChanges();
445 case 'd': // deactivate all but the directional lights
447 for(OSG::UInt16 i
= 0; i
< nlights
; ++i
)
449 if(lights
[i
]->getTypeId() !=
450 OSG::DirectionalLight::getClassTypeId())
452 lights
[i
]->setOn(false);
456 lights
[i
]->setOn(true);
459 OSG::commitChanges();
463 case 'p': // deactivate all but the point lights
465 for(OSG::UInt16 i
= 0; i
< nlights
; ++i
)
467 if(lights
[i
]->getTypeId() != OSG::PointLight::getClassTypeId())
469 lights
[i
]->setOn(false);
473 lights
[i
]->setOn(true);
476 OSG::commitChanges();
482 mgr
->setStatistics(!mgr
->getStatistics());
488 // setup the GLUT library which handles the windows for us
489 int setupGLUT(int *argc
, char *argv
[])
491 glutInit(argc
, argv
);
492 glutInitDisplayMode(GLUT_RGB
| GLUT_DEPTH
| GLUT_DOUBLE
);
494 int winid
= glutCreateWindow("OpenSG");
496 glutReshapeFunc(reshape
);
497 glutDisplayFunc(display
);
498 glutMouseFunc(mouse
);
499 glutMotionFunc(motion
);
500 glutKeyboardFunc(keyboard
);
502 // call the redraw function whenever there's nothing else to do
503 glutIdleFunc(display
);