root/branches/Carsten_PtrWork2/Tutorials/16lights.cpp

Revision 1039, 14.7 kB (checked in by cneumann, 11 months ago)

changed: - factory functions return a TransitPtr? that can not be implicitly

converted to C Ptr. Should help with porting.

added: - GlobalRefPtr?, needed for cases where upon return from main

a RefPtr? goes out of scope (it would attempt to access the
FCFactory which is already shutdown at that point).

status: - vrml loader does not compile (needs porting to ref ptr)

  • tutorials compile, run and exit cleanly
  • multithreading and cluster are untested, yet
  • Property svn:eol-style set to native
Line 
1 // OpenSG Tutorial Example: Lights
2 //
3 // This example shows how to create and manipulate light sources
4 //
5
6 // Headers
7 #include <OpenSG/OSGGLUT.h>
8 #include <OpenSG/OSGConfig.h>
9 #include <OpenSG/OSGSimpleGeometry.h>
10 #include <OpenSG/OSGGLUTWindow.h>
11 #include <OpenSG/OSGSimpleSceneManager.h>
12 #include <OpenSG/OSGTransform.h>
13 #include <OpenSG/OSGGroup.h>
14
15 // new header: the light sources
16 #include <OpenSG/OSGDirectionalLight.h>
17 #include <OpenSG/OSGPointLight.h>
18 #include <OpenSG/OSGSpotLight.h>
19
20 // Activate the OpenSG namespace
21 OSG_USING_NAMESPACE
22
23 UInt32                   nlights = 6;
24
25 TransformGlobalRefPtr    lightBeacons[8];
26 LightGlobalRefPtr        lights      [8];
27
28 // The SimpleSceneManager to manage simple applications
29 SimpleSceneManager *mgr;
30
31 // forward declaration so we can have the interesting stuff upfront
32 int setupGLUT( int *argc, char *argv[] );
33
34 // create the motion matrix for a light source at time t
35 void makeMatrix(Real32 t, Matrix &result)
36 {
37     Matrix m;
38    
39     result.setTransform(Quaternion(Vec3f(0,0,1), -Pi / 2));   
40    
41     m.setTransform(Vec3f(1, 0, 0));
42     result.multLeft(m);
43    
44     m.setTransform(Quaternion(Vec3f(0,1,0), t / 1000.f));   
45     result.multLeft(m);
46
47     m.setTransform(Vec3f(2, 0, 0));
48     result.multLeft(m);
49    
50     m.setTransform(Quaternion(Vec3f(0,0,1), t / 3000.f));
51     result.multLeft(m);
52 }
53
54 // redraw the window
55 void display( void )
56 {
57     // create the matrix
58     Real32 t = glutGet(GLUT_ELAPSED_TIME );
59    
60     // stagger the lights in time, so that they follow each other
61     for(UInt16 i = 0; i < nlights; ++i)
62     {
63         Matrix m;
64        
65         makeMatrix(t - 2000 * i, m);
66
67         lightBeacons[i]->setMatrix(m);
68     }
69     commitChanges();
70    
71     mgr->redraw();
72 }
73
74 // Initialize GLUT & OpenSG and set up the scene
75 int main(int argc, char **argv)
76 {
77     // OSG init
78     osgInit(argc,argv);
79
80     // GLUT init
81     int winid = setupGLUT(&argc, argv);
82
83     // Args given?
84     if(argc > 1)
85     {
86         if(sscanf(argv[1], "%d", &nlights) != 1)
87         {
88             FWARNING(("Number of lights '%s' not understood.\n", argv[1]));
89             nlights = 3;
90         }
91     }
92    
93     // the connection between GLUT and OpenSG
94     GLUTWindowGlobalRefPtr gwin= GLUTWindow::create();
95     gwin->setGlutId(winid);
96     gwin->init();
97
98     /*
99         A Light defines a source of light in the scene. Generally, two types
100         of information are of interest: The position of the light source
101         (geometry), and what elements of the scene are lit (semantics).
102
103         Using the position of the light in the graph for geometry allows
104         moving the Light just like any other node, by putting it below a
105         osg::Transform Node and changing the transformation. This consistency
106         also simplifies attaching Lights to moving parts in the scene: just
107         put them below the same Transform and they will move with the object.
108
109         The semantic interpretation also makes sense, it lets you restrict the
110         influence area of the light to a subgraph of the scene. This can be
111         used for efficiency, as every active light increases the amount of
112         calculations necessary per vertex, even if the light doesn't influence
113         the vertex, because it is too far away. It can also be used to
114         overcome the restrictions on the number of lights. OpenSG currently
115         only allows 8 concurrently active lights.
116
117         It is also not difficult to imagine situations where both
118         interpretations are necessary at the same time. Take for example a car
119         driving through a night scene. You'd want to headlights to be fixed to
120         the car and move together with it. But at the same time they should
121         light the houses you're driving by, and not the mountains in the
122         distance.
123
124         Thus there should be a way to do both at the same time. OpenSG solves
125         this by splitting the two tasks to two Nodes. The Light's Node is for
126         the sematntic part, it defines which object are lit by the Light. FOr
127         the geometrc part the Light keeps a SFNodePtr to a different Node, the
128         so called beacon. The local coordinate system of the beacon provides
129         the reference coordinate system for the light's position.
130
131
132         Thus the typical setup of an OpenSG scenegraph starts with a set of
133         lights, which light the whole scene, followed by the actual geometry.
134
135         Tip: Using the beacon of the camera (see \ref PageSystemWindowCamera)
136         as the beacon of a light source creates a headlight.
137
138         NOTE: Currently OpenSG does not implement the restricted influence
139         area. All Light sources are global and light the whole scene. Expect
140         that to change soon!
141
142         Every light is closely related to OpenGL's light specification. It has
143         a diffuse, specular and ambient color. Additionally it can be switched
144         on and off using the on field.
145     */
146
147
148     // Create the scene
149     
150     NodeGlobalRefPtr  scene = Node::create();
151     GroupGlobalRefPtr group = Group::create();
152     scene->setCore(group);
153
154     // create the scene to be lit
155
156     // a simple torus is fine for now.
157     // You can add more Geometry here if you want to.
158     NodeGlobalRefPtr lit_scene = makeTorus(.5, 2, 32, 64);
159
160     // helper node to keep the lights on top of each other
161     NodeGlobalRefPtr lastnode = lit_scene;
162
163     // create the light sources   
164     Color3f colors[] = { Color3f(1,0,0), Color3f(0,1,0), Color3f(0,0,1),
165                          Color3f(1,1,0), Color3f(0,1,1), Color3f(1,0,1),
166                          Color3f(1,1,1), Color3f(1,1,1)
167                        };       
168     if(nlights > 8)
169     {
170         FWARNING(("Currently only 8 lights supported\n"));
171         nlights = 8;
172     }
173    
174     // scale the lights to not overexpose everything. Just a little.
175     Real32 scale = osgMax(1., 1.5 / nlights);
176    
177     for(UInt16 i = 0; i < nlights; ++i)
178     {       
179         // create the light source
180         NodeRefPtr     light = Node::create();
181         LightRefPtr    light_core;
182         NodeRefPtr     geo_node;
183        
184         switch((i % 3) + 0)
185         {
186             /*
187                 The PointLight has a position to define its location. In
188                 addition, as it really is located in the scene, it has
189                 attenuation parameters to change the light's intensity
190                 depending on the distance to the light.
191
192                 Point lights are more expesinve to compute than directional
193                 lights, but not quite as expesive as spot lights. If you need
194                 to see the localized effects of the light, a point light is a
195                 good compromise between speed and quality.
196             */
197             case 0:
198             {
199                 PointLightRefPtr l = PointLight::create();
200                
201                 l->setPosition             (0, 0, 0);
202                 l->setConstantAttenuation  (1);
203                 l->setLinearAttenuation    (0);
204                 l->setQuadraticAttenuation (3);
205                
206                  // a little sphere to show where the light is
207                 geo_node = makeLatLongSphere(8, 8, 0.1);
208
209                 GeometryRefPtr       geo(dynamic_cast<GeometryPtr>(geo_node->getCore()));
210                 SimpleMaterialRefPtr sm (SimpleMaterial::create());
211
212                 sm->setLit(false);
213                 sm->setDiffuse(Color3f( colors[i][0],
214                                         colors[i][1],
215                                         colors[i][2] ));
216
217                 geo->setMaterial(sm);
218
219                 light_core = l;
220             }
221             break;
222            
223            
224             /*
225                 The DirectionalLight just has a direction.
226
227                 To use it as a headlight use (0,0,-1) as a direction. it is
228                 the computationally cheapest light source. Thus for the
229                 fastest lit rendering, just a single directional light source.
230                 The osg::SimpleSceneManager's headlight is a directional light
231                 source.
232
233             */
234             case 1:
235             {
236                 DirectionalLightRefPtr l = DirectionalLight::create();
237                
238                 l->setDirection(0, 0, 1);
239                
240                  // a little cylinder to show where the light is
241                 geo_node = makeCylinder(.1, .03, 8, true, true, true);
242
243                 GeometryRefPtr       geo(dynamic_cast<GeometryPtr>(geo_node->getCore()));
244                 SimpleMaterialRefPtr sm (SimpleMaterial::create());
245
246                 sm->setLit(false);
247                 sm->setDiffuse(Color3f( colors[i][0],
248                                         colors[i][1],
249                                         colors[i][2] ));
250
251                 geo->setMaterial(sm);
252
253                 light_core = l;
254             }
255             break;
256            
257             /*
258                 The SpotLight adds a direction to the PointLight and a
259                 spotCutOff angle to define the area that's lit. To define the
260                 light intensity fallof within that area the spotExponent field
261                 is used.
262
263                 Spot lights are very expensive to compute, use them sparingly.
264             */
265             case 2:
266             {
267                 SpotLightRefPtr l = SpotLight::create();
268                
269                 l->setPosition             (Pnt3f(0,  0, 0));
270                 l->setDirection            (Vec3f(0, -1, 0));
271                 l->setSpotExponent         (2);
272                 l->setSpotCutOff           (osgDegree2Rad(45));
273                 l->setConstantAttenuation  (1);
274                 l->setLinearAttenuation    (0);
275                 l->setQuadraticAttenuation (3);
276                
277                  // a little cone to show where the light is
278                 geo_node = makeCone(.2, .2, 8, true, true);
279
280                 GeometryRefPtr       geo(dynamic_cast<GeometryPtr>(geo_node->getCore()));
281                 SimpleMaterialRefPtr sm (SimpleMaterial::create());
282
283                 sm->setLit(false);
284                 sm->setDiffuse(Color3f( colors[i][0],
285                                         colors[i][1],
286                                         colors[i][2] ));
287
288                 geo->setMaterial(sm);
289
290                 light_core = l;
291             }
292             break;
293         }
294        
295         // create the beacon and attach it to the scene
296         NodeRefPtr         beacon      = Node::create();
297         TransformRefPtr    beacon_core = Transform::create();
298        
299         lightBeacons[i] = beacon_core;
300        
301         beacon->setCore(beacon_core);
302         beacon->addChild(geo_node);
303        
304         scene->addChild(beacon);
305                
306         light_core->setAmbient              (colors[i][0] / scale,
307                                              colors[i][1] / scale,
308                                              colors[i][2] / scale,
309                                              1);
310         light_core->setDiffuse              (colors[i][0] / scale,
311                                              colors[i][1] / scale,
312                                              colors[i][2] / scale,
313                                              1);
314         light_core->setSpecular             (1 / scale,
315                                              1 / scale,
316                                              1 / scale,
317                                              1);
318         light_core->setBeacon               (beacon);
319
320         light->setCore(light_core);
321         light->addChild(lastnode);
322        
323         lights[i] = light_core;
324         lastnode = light;
325     }
326
327     scene->addChild(lastnode);
328
329     commitChanges();
330
331     // create the SimpleSceneManager helper
332     mgr = new SimpleSceneManager;
333
334     // tell the manager what to manage
335     mgr->setWindow(gwin );
336     mgr->setRoot  (scene);
337    
338     // switch the headlight off, we have enough lights as is
339     mgr->setHeadlight(false);
340
341     // show the whole scene
342     mgr->showAll();
343
344     // GLUT main loop
345     glutMainLoop();
346
347     return 0;
348 }
349
350 //
351 // GLUT callback functions
352 //
353
354 // react to size changes
355 void reshape(int w, int h)
356 {
357     mgr->resize(w, h);
358     glutPostRedisplay();
359 }
360
361 // react to mouse button presses
362 void mouse(int button, int state, int x, int y)
363 {
364     if (state)
365         mgr->mouseButtonRelease(button, x, y);
366     else
367         mgr->mouseButtonPress(button, x, y);
368        
369     glutPostRedisplay();
370 }
371
372 // react to mouse motions with pressed buttons
373 void motion(int x, int y)
374 {
375     mgr->mouseMove(x, y);
376     glutPostRedisplay();
377 }
378
379 // react to keys
380 void keyboard(unsigned char k, int x, int y)
381 {
382     switch(k)
383     {
384         case 27:   
385         {
386             delete mgr;
387        
388             osgExit();
389             exit(1);
390         }
391         break;
392        
393         case 'a':   // activate all lights
394         {
395             for(UInt16 i = 0; i < nlights; ++i)
396             {
397                 lights[i]->setOn(true);
398             }
399         }
400         break;
401          
402         case 's':   // deactivate all but the spot lights
403         {
404             for(UInt16 i = 0; i < nlights; ++i)
405             {
406                 if(lights[i]->getTypeId() != SpotLight::getClassTypeId())
407                 {
408                     lights[i]->setOn(false);
409                 }
410                 else
411                 {
412                     lights[i]->setOn(true);
413                 }
414             }
415             commitChanges();
416         }
417         break;
418          
419         case 'd':   // deactivate all but the directional lights
420         {
421             for(UInt16 i = 0; i < nlights; ++i)
422             {
423                 if(lights[i]->getTypeId() != DirectionalLight::getClassTypeId())
424                 {
425                     lights[i]->setOn(false);
426                 }
427                 else
428                 {
429                     lights[i]->setOn(true);
430                 }
431             }
432             commitChanges();
433         }
434         break;
435          
436         case 'p':   // deactivate all but the point lights
437         {
438             for(UInt16 i = 0; i < nlights; ++i)
439             {
440                 if(lights[i]->getTypeId() != PointLight::getClassTypeId())
441                 {
442                     lights[i]->setOn(false);
443                 }
444                 else
445                 {
446                     lights[i]->setOn(true);
447                 }
448             }
449             commitChanges();
450         }
451         break;
452
453         case 'S':
454         {
455             mgr->setStatistics(!mgr->getStatistics());
456         }
457         break;
458    }
459 }
460
461 // setup the GLUT library which handles the windows for us
462 int setupGLUT(int *argc, char *argv[])
463 {
464     glutInit(argc, argv);
465     glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
466    
467     int winid = glutCreateWindow("OpenSG");
468    
469     glutReshapeFunc(reshape);
470     glutDisplayFunc(display);
471     glutMouseFunc(mouse);
472     glutMotionFunc(motion);
473     glutKeyboardFunc(keyboard);
474
475     // call the redraw function whenever there's nothing else to do
476     glutIdleFunc(display);
477
478     return winid;
479 }
Note: See TracBrowser for help on using the browser.