fixed: auto_ptr -> unique_ptr
[opensg.git] / Examples / Simple / lights.cpp
blob031bd99a3cc6e7f805c0105a8f24d88617daed65
1 // OpenSG Tutorial Example: Lights
2 //
3 // This example shows how to create and manipulate light sources
4 //
6 #ifdef OSG_BUILD_ACTIVE
7 // Headers
8 #include <OSGGLUT.h>
9 #include <OSGConfig.h>
10 #include <OSGSimpleGeometry.h>
11 #include <OSGGLUTWindow.h>
12 #include <OSGSimpleSceneManager.h>
13 #include <OSGTransform.h>
14 #include <OSGGroup.h>
16 // new header: the light sources
17 #include <OSGDirectionalLight.h>
18 #include <OSGPointLight.h>
19 #include <OSGSpotLight.h>
20 #else
21 // Headers
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>
34 #endif
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)
50 OSG::Matrix m;
52 result.setTransform(OSG::Quaternion(OSG::Vec3f(0,0,1), -OSG::Pi / 2));
54 m.setTransform(OSG::Vec3f(1, 0, 0));
55 result.multLeft(m);
57 m.setTransform(OSG::Quaternion(OSG::Vec3f(0,1,0), t / 1000.f));
58 result.multLeft(m);
60 m.setTransform(OSG::Vec3f(2, 0, 0));
61 result.multLeft(m);
63 m.setTransform(OSG::Quaternion(OSG::Vec3f(0,0,1), t / 3000.f));
64 result.multLeft(m);
67 // redraw the window
68 void display( void )
70 // create the matrix
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)
76 OSG::Matrix m;
78 makeMatrix(t - 2000 * i, m);
80 lightBeacons[i]->setMatrix(m);
82 OSG::commitChanges();
84 mgr->redraw();
87 // Initialize GLUT & OpenSG and set up the scene
88 int main(int argc, char **argv)
90 // OSG init
91 OSG::osgInit(argc,argv);
93 // GLUT init
94 int winid = setupGLUT(&argc, argv);
96 // Args given?
97 if(argc > 1)
99 if(sscanf(argv[1], "%u", &nlights) != 1)
101 FWARNING(("Number of lights '%s' not understood.\n", argv[1]));
102 nlights = 3;
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);
114 gwin->init();
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
140 distance.
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.
163 // Create the scene
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)
185 if(nlights > 8)
187 FWARNING(("Currently only 8 lights supported\n"));
188 nlights = 8;
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;
201 switch((i % 3) + 0)
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.
214 case 0:
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();
231 sm->setLit(false);
232 sm->setDiffuse(OSG::Color3f( colors[i][0],
233 colors[i][1],
234 colors[i][2] ));
236 geo->setMaterial(sm);
238 light_core = l;
240 break;
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
250 source.
253 case 1:
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();
268 sm->setLit(false);
269 sm->setDiffuse(OSG::Color3f( colors[i][0],
270 colors[i][1],
271 colors[i][2] ));
273 geo->setMaterial(sm);
275 light_core = l;
277 break;
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
283 is used.
285 Spot lights are very expensive to compute, use them sparingly.
287 case 2:
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();
307 sm->setLit(false);
308 sm->setDiffuse(OSG::Color3f( colors[i][0],
309 colors[i][1],
310 colors[i][2] ));
312 geo->setMaterial(sm);
314 light_core = l;
316 break;
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,
339 1 / scale,
340 1 / scale,
342 light_core->setBeacon (beacon);
344 light->setCore(light_core);
345 light->addChild(lastnode);
347 lights[i] = light_core;
348 lastnode = light;
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
366 mgr->showAll();
369 // GLUT main loop
370 glutMainLoop();
372 return 0;
376 // GLUT callback functions
379 // react to size changes
380 void reshape(int w, int h)
382 mgr->resize(w, h);
383 glutPostRedisplay();
386 // react to mouse button presses
387 void mouse(int button, int state, int x, int y)
389 if (state)
390 mgr->mouseButtonRelease(button, x, y);
391 else
392 mgr->mouseButtonPress(button, x, y);
394 glutPostRedisplay();
397 // react to mouse motions with pressed buttons
398 void motion(int x, int y)
400 mgr->mouseMove(x, y);
401 glutPostRedisplay();
404 // react to keys
405 void keyboard(unsigned char k, int x, int y)
407 switch(k)
409 case 27:
411 // clean up global variables
412 mgr = NULL;
414 OSG::osgExit();
415 exit(1);
417 break;
419 case 'a': // activate all lights
421 for(OSG::UInt16 i = 0; i < nlights; ++i)
423 lights[i]->setOn(true);
426 break;
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);
436 else
438 lights[i]->setOn(true);
441 OSG::commitChanges();
443 break;
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);
454 else
456 lights[i]->setOn(true);
459 OSG::commitChanges();
461 break;
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);
471 else
473 lights[i]->setOn(true);
476 OSG::commitChanges();
478 break;
480 case 'S':
482 mgr->setStatistics(!mgr->getStatistics());
484 break;
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);
505 return winid;