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

Revision 835, 14.6 kB (checked in by vossg, 1 year ago)

ported : cluster windows (basic port still need quite some testing and verification)
added : ptr mfield copy to containers
fixed : tutorial compile problems

  • 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 TransformPtr    lightBeacons[8];
26 LightPtr        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     GLUTWindowPtr 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     NodePtr scene = Node::create();
151     GroupPtr group = Group::create();
152     scene->setCore(group);
153     // keep it open, will be needed below
154
155     // create the scene to be lit
156
157     // a simple torus is fine for now.
158     // You can add more Geometry here if you want to.
159     NodePtr lit_scene = makeTorus(.5, 2, 32, 64);
160
161     // helper node to keep the lights on top of each other
162     NodePtr lastnode = lit_scene;
163
164     // create the light sources   
165     Color3f colors[] = { Color3f(1,0,0), Color3f(0,1,0), Color3f(0,0,1),
166                          Color3f(1,1,0), Color3f(0,1,1), Color3f(1,0,1),
167                          Color3f(1,1,1), Color3f(1,1,1)
168                        };       
169     if(nlights > 8)
170     {
171         FWARNING(("Currently only 8 lights supported\n"));
172         nlights = 8;
173     }
174    
175     // scale the lights to not overexpose everything. Just a little.
176     Real32 scale = osgMax(1., 1.5 / nlights);
177    
178     for(UInt16 i = 0; i < nlights; ++i)
179     {       
180         // create the light source
181         NodePtr     light = Node::create();
182         LightPtr    light_core;
183         NodePtr     geo_node;
184        
185         switch((i % 3) + 0)
186         {
187             /*
188                 The PointLight has a position to define its location. In
189                 addition, as it really is located in the scene, it has
190                 attenuation parameters to change the light's intensity
191                 depending on the distance to the light.
192
193                 Point lights are more expesinve to compute than directional
194                 lights, but not quite as expesive as spot lights. If you need
195                 to see the localized effects of the light, a point light is a
196                 good compromise between speed and quality.
197             */
198             case 0:
199             {
200                 PointLightPtr l = PointLight::create();
201                
202                 l->setPosition             (0, 0, 0);
203                 l->setConstantAttenuation  (1);
204                 l->setLinearAttenuation    (0);
205                 l->setQuadraticAttenuation (3);
206                
207                  // a little sphere to show where the light is
208                 geo_node = makeLatLongSphere(8, 8, 0.1);
209
210                 GeometryPtr geo = dynamic_cast<GeometryPtr>(geo_node->getCore());
211
212                 SimpleMaterialPtr sm = SimpleMaterial::create();
213
214                 sm->setLit(false);
215                 sm->setDiffuse(Color3f( colors[i][0],
216                                         colors[i][1],
217                                         colors[i][2] ));
218
219                 geo->setMaterial(sm);
220
221                 light_core = l;
222             }
223             break;
224            
225            
226             /*
227                 The DirectionalLight just has a direction.
228
229                 To use it as a headlight use (0,0,-1) as a direction. it is
230                 the computationally cheapest light source. Thus for the
231                 fastest lit rendering, just a single directional light source.
232                 The osg::SimpleSceneManager's headlight is a directional light
233                 source.
234
235             */
236             case 1:
237             {
238                 DirectionalLightPtr l = DirectionalLight::create();
239                
240                 l->setDirection(0, 0, 1);
241                
242                  // a little cylinder to show where the light is
243                 geo_node = makeCylinder(.1, .03, 8, true, true, true);
244
245                 GeometryPtr geo = dynamic_cast<GeometryPtr>(geo_node->getCore());
246
247                 SimpleMaterialPtr sm = SimpleMaterial::create();
248
249                 sm->setLit(false);
250                 sm->setDiffuse(Color3f( colors[i][0],
251                                         colors[i][1],
252                                         colors[i][2] ));
253
254                 geo->setMaterial(sm);
255
256                 light_core = l;
257             }
258             break;
259            
260             /*
261                 The SpotLight adds a direction to the PointLight and a
262                 spotCutOff angle to define the area that's lit. To define the
263                 light intensity fallof within that area the spotExponent field
264                 is used.
265
266                 Spot lights are very expensive to compute, use them sparingly.
267             */
268             case 2:
269             {
270                 SpotLightPtr l = SpotLight::create();
271                
272                 l->setPosition             (Pnt3f(0,  0, 0));
273                 l->setDirection            (Vec3f(0, -1, 0));
274                 l->setSpotExponent         (2);
275                 l->setSpotCutOff           (osgDegree2Rad(45));
276                 l->setConstantAttenuation  (1);
277                 l->setLinearAttenuation    (0);
278                 l->setQuadraticAttenuation (3);
279                
280                  // a little cone to show where the light is
281                 geo_node = makeCone(.2, .2, 8, true, true);
282
283                 GeometryPtr geo = dynamic_cast<GeometryPtr>(geo_node->getCore());
284
285                 SimpleMaterialPtr sm = SimpleMaterial::create();
286
287                 sm->setLit(false);
288                 sm->setDiffuse(Color3f( colors[i][0],
289                                         colors[i][1],
290                                         colors[i][2] ));
291
292                 geo->setMaterial(sm);
293
294                 light_core = l;
295             }
296             break;
297         }
298        
299         // create the beacon and attach it to the scene
300         NodePtr         beacon      = Node::create();
301         TransformPtr    beacon_core = Transform::create();
302        
303         lightBeacons[i] = beacon_core;
304        
305         beacon->setCore(beacon_core);
306         beacon->addChild(geo_node);
307        
308         scene->addChild(beacon);
309                
310         light_core->setAmbient              (colors[i][0] / scale,
311                                              colors[i][1] / scale,
312                                              colors[i][2] / scale,
313                                              1);
314         light_core->setDiffuse              (colors[i][0] / scale,
315                                              colors[i][1] / scale,
316                                              colors[i][2] / scale,
317                                              1);
318         light_core->setSpecular             (1 / scale,
319                                              1 / scale,
320                                              1 / scale,
321                                              1);
322         light_core->setBeacon               (beacon);
323
324         light->setCore(light_core);
325         light->addChild(lastnode);
326        
327         lights[i] = light_core;
328         lastnode = light;
329     }
330
331     scene->addChild(lastnode);
332
333     commitChanges();
334
335     // create the SimpleSceneManager helper
336     mgr = new SimpleSceneManager;
337
338     // tell the manager what to manage
339     mgr->setWindow(gwin );
340     mgr->setRoot  (scene);
341    
342     // switch the headlight off, we have enough lights as is
343     mgr->setHeadlight(false);
344
345     // show the whole scene
346     mgr->showAll();
347
348     // GLUT main loop
349     glutMainLoop();
350
351     return 0;
352 }
353
354 //
355 // GLUT callback functions
356 //
357
358 // react to size changes
359 void reshape(int w, int h)
360 {
361     mgr->resize(w, h);
362     glutPostRedisplay();
363 }
364
365 // react to mouse button presses
366 void mouse(int button, int state, int x, int y)
367 {
368     if (state)
369         mgr->mouseButtonRelease(button, x, y);
370     else
371         mgr->mouseButtonPress(button, x, y);
372        
373     glutPostRedisplay();
374 }
375
376 // react to mouse motions with pressed buttons
377 void motion(int x, int y)
378 {
379     mgr->mouseMove(x, y);
380     glutPostRedisplay();
381 }
382
383 // react to keys
384 void keyboard(unsigned char k, int x, int y)
385 {
386     switch(k)
387     {
388         case 27:   
389         {
390             osgExit();
391             exit(1);
392         }
393         break;
394        
395         case 'a':   // activate all lights
396         {
397             for(UInt16 i = 0; i < nlights; ++i)
398             {
399                 lights[i]->setOn(true);
400             }
401         }
402         break;
403          
404         case 's':   // deactivate all but the spot lights
405         {
406             for(UInt16 i = 0; i < nlights; ++i)
407             {
408                 if(lights[i]->getTypeId() != SpotLight::getClassTypeId())
409                 {
410                     lights[i]->setOn(false);
411                 }
412                 else
413                 {
414                     lights[i]->setOn(true);
415                 }
416             }
417             commitChanges();
418         }
419         break;
420          
421         case 'd':   // deactivate all but the directional lights
422         {
423             for(UInt16 i = 0; i < nlights; ++i)
424             {
425                 if(lights[i]->getTypeId() != DirectionalLight::getClassTypeId())
426                 {
427                     lights[i]->setOn(false);
428                 }
429                 else
430                 {
431                     lights[i]->setOn(true);
432                 }
433             }
434             commitChanges();
435         }
436         break;
437          
438         case 'p':   // deactivate all but the point lights
439         {
440             for(UInt16 i = 0; i < nlights; ++i)
441             {
442                 if(lights[i]->getTypeId() != PointLight::getClassTypeId())
443                 {
444                     lights[i]->setOn(false);
445                 }
446                 else
447                 {
448                     lights[i]->setOn(true);
449                 }
450             }
451             commitChanges();
452         }
453         break;
454
455         case 'S':
456         {
457             mgr->setStatistics(!mgr->getStatistics());
458         }
459         break;
460    }
461 }
462
463 // setup the GLUT library which handles the windows for us
464 int setupGLUT(int *argc, char *argv[])
465 {
466     glutInit(argc, argv);
467     glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
468    
469     int winid = glutCreateWindow("OpenSG");
470    
471     glutReshapeFunc(reshape);
472     glutDisplayFunc(display);
473     glutMouseFunc(mouse);
474     glutMotionFunc(motion);
475     glutKeyboardFunc(keyboard);
476
477     // call the redraw function whenever there's nothing else to do
478     glutIdleFunc(display);
479
480     return winid;
481 }
Note: See TracBrowser for help on using the browser.