// react to keys void keyboard(unsigned char k, int , int ) { switch (k) { case 27: { mgr = NULL; delete gTextStuff; OSG::commitChanges(); OSG::osgExit(); exit(0); } break; case '-': gTextStuff->incFaceSize(false); break; case '=': gTextStuff->incFaceSize(true); break; case '[': gTextStuff->incTextureSize(false); break; case ']': gTextStuff->incTextureSize(true); break; case '<': gTextStuff->incMaxExtent(false); break; case '>': gTextStuff->incMaxExtent(true); break; case ',': gTextStuff->incLineSpacing(false); break; case '.': gTextStuff->incLineSpacing(true); break; case '{': gTextStuff->incGeoScale(false); break; case '}': gTextStuff->incGeoScale(true); break; case 'f': gTextStuff->goToNextFamily(); break; case 'd': OSG::SceneFileHandler::the()->write(mgr->getRoot(),"dump_scene.osb"); std::cout << "Wrote out scene: dump_scene.osb" << std::endl; break; case 't': mgr->setNavigationMode(OSG::Navigator::TRACKBALL); break; case 'l': mgr->setHeadlight(!mgr->getHeadlightState()); std::cout << "Set headlight: " << mgr->getHeadlightState() << std::endl; break; case 'z': glPolygonMode( GL_FRONT_AND_BACK, GL_POINT); std::cerr << "PolygonMode: Point." << std::endl; break; case 'x': glPolygonMode( GL_FRONT_AND_BACK, GL_LINE); std::cerr << "PolygonMode: Line." << std::endl; break; case 'c': glPolygonMode( GL_FRONT_AND_BACK, GL_FILL); std::cerr << "PolygonMode: Fill." << std::endl; break; case 'h': std::cerr << "Keys:" << std::endl; std::cerr << "- =: change face size" << std::endl; std::cerr << "{ }: change geo scale" << std::endl; std::cerr << "[ ]: change texture size" << std::endl; std::cerr << "< >: change max extend for 1st line" << std::endl; std::cerr << ", .: change line spacing" << std::endl; std::cerr << "f : next font family" << std::endl; std::cerr << "d : dump scene" << std::endl; } }
// react to keys void keyboard(unsigned char k, int , int ) { switch(k) { case 27: { cleanup(); OSG::osgExit(); std::exit(0); } break; case 'f': { mgr->setNavigationMode(OSG::Navigator::FLY); std::cout << "Fly mode" << std::endl; } break; case 't': { mgr->setNavigationMode(OSG::Navigator::TRACKBALL); std::cout << "Trackball mode" << std::endl; } break; case 'q': { mgr->setStatistics(!mgr->getStatistics()); std::cout << "Statistics " << (mgr->getStatistics() ? "enabled" : "disabled") << std::endl; } break; case 'h': { mgr->setHeadlight(!mgr->getHeadlightState()); std::cout << "Headlight " << (mgr->getHeadlightState() ? "enabled" : "disabled") << std::endl; } break; case 'b': { if(polyChunk == NULL) { polyChunk = OSG::PolygonChunk::create(); root->addChunk(polyChunk); } if(polyChunk->getCullFace() == GL_NONE) { polyChunk->setCullFace(GL_BACK); std::cout << "Backface culling enabled" << std::endl; } else { polyChunk->setCullFace(GL_NONE); std::cout << "Backface culling disabled" << std::endl; } } break; case 'w': { if(polyChunk == NULL) { polyChunk = OSG::PolygonChunk::create(); root->addChunk(polyChunk); } if(polyChunk->getFrontMode() == GL_FILL) { polyChunk->setFrontMode(GL_LINE); polyChunk->setBackMode (GL_LINE); std::cout << "Wireframe enabled" << std::endl; } else { polyChunk->setFrontMode(GL_FILL); polyChunk->setBackMode (GL_FILL); std::cout << "Wireframe disabled" << std::endl; } } break; case 'n': { if(normalsActive == true) { normalsActive = false; NodeStore::const_iterator ngIt = normalsGeoN.begin(); NodeStore::const_iterator ngEnd = normalsGeoN.end (); for(; ngIt != ngEnd; ++ngIt) { (*ngIt)->setTravMask(0); } std::cout << "Normals disabled" << std::endl; } else { normalsActive = true; if(normalsGeoN.empty() == true) constructNormalsGeo(sceneN); NodeStore::const_iterator ngIt = normalsGeoN.begin(); NodeStore::const_iterator ngEnd = normalsGeoN.end (); for(; ngIt != ngEnd; ++ngIt) { (*ngIt)->setTravMask(OSG::TypeTraits<OSG::UInt32>::BitsSet); } std::cout << "Normals enabled" << std::endl; } } break; case 'm': { normalsLen /= 1.25f; constructNormalsGeo(sceneN); std::cout << "Normals length " << normalsLen << std::endl; } break; case 'M': { normalsLen *= 1.25f; constructNormalsGeo(sceneN); std::cout << "Normals length " << normalsLen << std::endl; } break; case 'v': { mgr->getRenderAction()->setVolumeDrawing( !mgr->getRenderAction()->getVolumeDrawing()); std::cout << "Volume drawing: " << (mgr->getRenderAction()->getVolumeDrawing() ? "enabled" : "disabled") << std::endl; } break; case 'p': { OSG::SceneGraphPrinter sgp(mgr->getRoot()); sgp.addPrintFunc(OSG::SkinnedGeometry::getClassType(), &printVolume ); sgp.printDownTree(std::cout); NodeStore::const_iterator nIt = skinnedGeoN.begin(); NodeStore::const_iterator nEnd = skinnedGeoN.end (); for(OSG::UInt32 i = 0; nIt != nEnd; ++nIt, ++i) { OSG::SkinnedGeometry *sgeo = dynamic_cast<OSG::SkinnedGeometry *>( (*nIt)->getCore()); std::cout << "Skeleton:\n"; OSG::SceneGraphPrinter skelPrinter(sgeo->getSkeleton()->getRoots(0)); skelPrinter.addPrintFunc(OSG::Transform ::getClassType(), &printXForm ); //skelPrinter.addPrintFunc(OSG::SkeletonJoint::getClassType(), // &printJoint ); skelPrinter.printDownTree(std::cout); } } break; case 'a': { mgr->showAll(); std::cout << "Showing all of scene." << std::endl; } break; case '[': { if(anims.empty() == false) { currAnim -= 1; if(currAnim < 0) currAnim = anims.size() - 1; std::cout << "Current anim [" << currAnim << "] - [" << anims[currAnim].anim->getTemplate()->getName() << "]" << std::endl; } } break; case ']': { if(anims.empty() == false) { currAnim += 1; if(currAnim >= OSG::Int32(anims.size())) currAnim = 0; std::cout << "Current anim [" << currAnim << "] - [" << anims[currAnim].anim->getTemplate()->getName() << "]" << std::endl; } } break; case 'L': { toggleAnim(currAnim, false); } break; case 'l': { toggleAnim(currAnim, true); } break; case 'd': { NodeStore::const_iterator nIt = skinnedGeoN.begin(); NodeStore::const_iterator nEnd = skinnedGeoN.end (); for(OSG::UInt32 i = 0; nIt != nEnd; ++nIt, ++i) { OSG::SkinnedGeometry *sgeo = dynamic_cast<OSG::SkinnedGeometry *>( (*nIt)->getCore()); if(sgeo->getRenderMode() == OSG::SkinnedGeometry::RMSkinnedCPU) { std::cout << "Enabling SkinnedGeo GPU mode [" << sgeo << "]" << std::endl; sgeo->setRenderMode(OSG::SkinnedGeometry::RMSkinnedGPU); sgeo->setMaterial (matSkin); } else if(sgeo->getRenderMode() == OSG::SkinnedGeometry::RMSkinnedGPU) { std::cout << "Enabling SkinnedGeo SKELETON mode [" << sgeo << "]" << std::endl; sgeo->setRenderMode(OSG::SkinnedGeometry::RMSkeleton); sgeo->setMaterial (skinnedGeoMat[i]); } else if(sgeo->getRenderMode() == OSG::SkinnedGeometry::RMSkeleton) { std::cout << "Enabling SkinnedGeo UNSKINNED mode [" << sgeo << "]" << std::endl; sgeo->setRenderMode(OSG::SkinnedGeometry::RMUnskinned); sgeo->setMaterial (skinnedGeoMat[i]); } else { std::cout << "Enabling SkinnedGeo CPU mode [" << sgeo << "]" << std::endl; sgeo->setRenderMode(OSG::SkinnedGeometry::RMSkinnedCPU); sgeo->setMaterial(skinnedGeoMat[i]); } } } break; case 'c': { mgr->getRenderAction()->setFrustumCulling( !mgr->getRenderAction()->getFrustumCulling()); std::cout << "Frustum culling: " << (mgr->getRenderAction()->getFrustumCulling() ? "enabled" : "disabled") << std::endl; } break; case 's': { NodeStore::const_iterator nIt = skinnedGeoN.begin(); NodeStore::const_iterator nEnd = skinnedGeoN.end (); for(OSG::UInt32 i = 0; nIt != nEnd; ++nIt, ++i) { OSG::SkinnedGeometry *sgeo = dynamic_cast<OSG::SkinnedGeometry *>( (*nIt)->getCore()); OSG::Skeleton *skel = sgeo->getSkeleton(); OSG::Skeleton::MFRootsType::const_iterator rIt = skel->getMFRoots()->begin(); OSG::Skeleton::MFRootsType::const_iterator rEnd = skel->getMFRoots()->end (); for(OSG::UInt32 j = 0; rIt != rEnd; ++rIt, ++j) { std::cout << "Skeleton [" << i << "] @ [" << skel << "] root [" << j << "]\n"; OSG::SceneGraphPrinter sgp(*rIt); sgp.printDownTree(std::cout); std::cout << std::endl; } } } break; default: { printHelp(); } break; } glutPostRedisplay(); }
// Initialize GLUT & OpenSG and set up the scene int main(int argc, char **argv) { // OSG init OSG::osgInit(argc,argv); // GLUT init int winid = setupGLUT(&argc, argv); // Args given? if(argc > 1) { if(sscanf(argv[1], "%u", &nlights) != 1) { FWARNING(("Number of lights '%s' not understood.\n", argv[1])); nlights = 3; } } // open a new scope, because the pointers below should go out of scope // before entering glutMainLoop. // Otherwise OpenSG will complain about objects being alive after shutdown. { // the connection between GLUT and OpenSG OSG::GLUTWindowRefPtr gwin = OSG::GLUTWindow::create(); gwin->setGlutId(winid); gwin->init(); /* A Light defines a source of light in the scene. Generally, two types of information are of interest: The position of the light source (geometry), and what elements of the scene are lit (semantics). Using the position of the light in the graph for geometry allows moving the Light just like any other node, by putting it below a OSG::Transform Node and changing the transformation. This consistency also simplifies attaching Lights to moving parts in the scene: just put them below the same Transform and they will move with the object. The semantic interpretation also makes sense, it lets you restrict the influence area of the light to a subgraph of the scene. This can be used for efficiency, as every active light increases the amount of calculations necessary per vertex, even if the light doesn't influence the vertex, because it is too far away. It can also be used to overcome the restrictions on the number of lights. OpenSG currently only allows 8 concurrently active lights. It is also not difficult to imagine situations where both interpretations are necessary at the same time. Take for example a car driving through a night scene. You'd want to headlights to be fixed to the car and move together with it. But at the same time they should light the houses you're driving by, and not the mountains in the distance. Thus there should be a way to do both at the same time. OpenSG solves this by splitting the two tasks to two Nodes. The Light's Node is for the sematntic part, it defines which object are lit by the Light. FOr the geometrc part the Light keeps a SFNodePtr to a different Node, the so called beacon. The local coordinate system of the beacon provides the reference coordinate system for the light's position. Thus the typical setup of an OpenSG scenegraph starts with a set of lights, which light the whole scene, followed by the actual geometry. Tip: Using the beacon of the camera (see \ref PageSystemWindowCamera) as the beacon of a light source creates a headlight. Every light is closely related to OpenGL's light specification. It has a diffuse, specular and ambient color. Additionally it can be switched on and off using the on field. */ // Create the scene OSG::NodeRefPtr scene = OSG::Node::create(); OSG::GroupRefPtr group = OSG::Group::create(); scene->setCore(group); // create the scene to be lit // a simple torus is fine for now. // You can add more Geometry here if you want to. OSG::NodeRefPtr lit_scene = OSG::makeTorus(.5, 2, 32, 64); // helper node to keep the lights on top of each other OSG::NodeRefPtr lastnode = lit_scene; // create the light sources OSG::Color3f colors[] = { OSG::Color3f(1,0,0), OSG::Color3f(0,1,0), OSG::Color3f(0,0,1), OSG::Color3f(1,1,0), OSG::Color3f(0,1,1), OSG::Color3f(1,0,1), OSG::Color3f(1,1,1), OSG::Color3f(1,1,1) }; if(nlights > 8) { FWARNING(("Currently only 8 lights supported\n")); nlights = 8; } // scale the lights to not overexpose everything. Just a little. OSG::Real32 scale = OSG::osgMax(1., 1.5 / nlights); for(OSG::UInt16 i = 0; i < nlights; ++i) { // create the light source OSG::NodeRefPtr light = OSG::Node::create(); OSG::LightRefPtr light_core; OSG::NodeRefPtr geo_node; switch((i % 3) + 0) { /* The PointLight has a position to define its location. In addition, as it really is located in the scene, it has attenuation parameters to change the light's intensity depending on the distance to the light. Point lights are more expesinve to compute than directional lights, but not quite as expesive as spot lights. If you need to see the localized effects of the light, a point light is a good compromise between speed and quality. */ case 0: { OSG::PointLightRefPtr l = OSG::PointLight::create(); l->setPosition (0, 0, 0); l->setConstantAttenuation (1); l->setLinearAttenuation (0); l->setQuadraticAttenuation (3); // a little sphere to show where the light is geo_node = OSG::makeLatLongSphere(8, 8, 0.1f); OSG::GeometryRefPtr geo = dynamic_cast<OSG::Geometry *>(geo_node->getCore()); OSG::SimpleMaterialRefPtr sm = OSG::SimpleMaterial::create(); sm->setLit(false); sm->setDiffuse(OSG::Color3f( colors[i][0], colors[i][1], colors[i][2] )); geo->setMaterial(sm); light_core = l; } break; /* The DirectionalLight just has a direction. To use it as a headlight use (0,0,-1) as a direction. it is the computationally cheapest light source. Thus for the fastest lit rendering, just a single directional light source. The osg::SimpleSceneManager's headlight is a directional light source. */ case 1: { OSG::DirectionalLightRefPtr l = OSG::DirectionalLight::create(); l->setDirection(0, 0, 1); // a little cylinder to show where the light is geo_node = OSG::makeCylinder(.1f, .03f, 8, true, true, true); OSG::GeometryRefPtr geo = dynamic_cast<OSG::Geometry *>(geo_node->getCore()); OSG::SimpleMaterialRefPtr sm = OSG::SimpleMaterial::create(); sm->setLit(false); sm->setDiffuse(OSG::Color3f( colors[i][0], colors[i][1], colors[i][2] )); geo->setMaterial(sm); light_core = l; } break; /* The SpotLight adds a direction to the PointLight and a spotCutOff angle to define the area that's lit. To define the light intensity fallof within that area the spotExponent field is used. Spot lights are very expensive to compute, use them sparingly. */ case 2: { OSG::SpotLightRefPtr l = OSG::SpotLight::create(); l->setPosition (OSG::Pnt3f(0, 0, 0)); l->setDirection (OSG::Vec3f(0, -1, 0)); l->setSpotExponent (2); l->setSpotCutOff (OSG::osgDegree2Rad(45)); l->setConstantAttenuation (1); l->setLinearAttenuation (0); l->setQuadraticAttenuation (3); // a little cone to show where the light is geo_node = OSG::makeCone(.2f, .2f, 8, true, true); OSG::GeometryRefPtr geo = dynamic_cast<OSG::Geometry *>(geo_node->getCore()); OSG::SimpleMaterialRefPtr sm = OSG::SimpleMaterial::create(); sm->setLit(false); sm->setDiffuse(OSG::Color3f( colors[i][0], colors[i][1], colors[i][2] )); geo->setMaterial(sm); light_core = l; } break; } // create the beacon and attach it to the scene OSG::NodeRefPtr beacon = OSG::Node::create(); OSG::TransformRefPtr beacon_core = OSG::Transform::create(); lightBeacons[i] = beacon_core; beacon->setCore(beacon_core); beacon->addChild(geo_node); scene->addChild(beacon); light_core->setAmbient (colors[i][0] / scale, colors[i][1] / scale, colors[i][2] / scale, 1); light_core->setDiffuse (colors[i][0] / scale, colors[i][1] / scale, colors[i][2] / scale, 1); light_core->setSpecular(1 / scale, 1 / scale, 1 / scale, 1); light_core->setBeacon (beacon); light->setCore(light_core); light->addChild(lastnode); lights[i] = light_core; lastnode = light; } scene->addChild(lastnode); OSG::commitChanges(); // create the SimpleSceneManager helper mgr = OSG::SimpleSceneManager::create(); // tell the manager what to manage mgr->setWindow(gwin ); mgr->setRoot (scene); // switch the headlight off, we have enough lights as is mgr->setHeadlight(false); // show the whole scene mgr->showAll(); } // GLUT main loop glutMainLoop(); return 0; }