void combineVertexAttributes( dp::sg::ui::ViewStateSharedPtr const& viewState ) { DP_ASSERT( viewState && viewState->getScene() && viewState->getScene()->getRootNode() ); std::vector<dp::sg::core::ObjectSharedPtr> results = dp::sg::algorithm::searchClass( viewState->getScene()->getRootNode(), "class::dp::sg::core::VertexAttributeSet" ); for ( std::vector<dp::sg::core::ObjectSharedPtr>::iterator it = results.begin(); it != results.end(); ++it ) { it->inplaceCast<dp::sg::core::VertexAttributeSet>()->combineBuffers(); } }
void SceneRenderer::beginRendering( dp::sg::ui::ViewStateSharedPtr const& viewState, dp::ui::RenderTargetSharedPtr const& renderTarget ) { DP_ASSERT( viewState ); if ( viewState ) { DP_ASSERT( viewState->getRendererOptions() ); if( viewState->getRendererOptions() && viewState->getRendererOptions() != m_rendererOptions.getSharedPtr() ) { // update renderer options m_rendererOptions = viewState->getRendererOptions().getWeakPtr(); addRendererOptions( viewState->getRendererOptions() ); } } }
bool saveScene( std::string const& filename, dp::sg::ui::ViewStateSharedPtr const& viewState, dp::util::PlugInCallback *callback ) { bool result = false; // define a unique plug-interface ID for SceneLoader const dp::util::UPITID PITID_SCENE_SAVER(UPITID_SCENE_SAVER, UPITID_VERSION); dp::util::FileFinder fileFinder( dp::util::getCurrentPath() ); fileFinder.addSearchPath( dp::util::getModulePath() ); #if defined(DP_OS_WINDOWS) fileFinder.addSearchPath( dp::util::getModulePath( reinterpret_cast<HMODULE>(&__ImageBase) ) ); #endif dp::util::UPIID piid = dp::util::UPIID(dp::util::getFileExtension( filename ).c_str(), PITID_SCENE_SAVER); { dp::util::PlugInSharedPtr plug; if ( getInterface( fileFinder, piid, plug ) ) { SceneSaverSharedPtr ss = std::static_pointer_cast<SceneSaver>(plug); try { dp::sg::core::SceneSharedPtr scene( viewState->getScene() ); // DAR HACK Change SceneSaver interface later. result = ss->save( scene, viewState, filename ); } catch(...) // catch all others { } } } // FIXME interface needs to be released since the cleanup order (first dp::sg::core, then dp::util) causes problems upon destruction. dp::util::releaseInterface(piid); return result; }
void SceneRendererPipeline::doRenderStandard(dp::sg::ui::ViewStateSharedPtr const& viewState, dp::ui::RenderTargetSharedPtr const& renderTarget) { // Call the current scene renderer and render the whole scene into the main render target (tonemapFBO). DP_ASSERT( viewState->getTraversalMask() == ~0 ); // This renders only one eye even if the renderTarget is stereoscopic. // Important: The m_sceneRenderer holds a NOP StereoViewStateProvider to use the already adjusted stereo ViewState camera! m_sceneRenderer->render(viewState, renderTarget, renderTarget->getStereoTarget()); }
void setLights( size_t counter = ~0 ) { if( !g_lightSources[0] ) { dp::sg::core::GroupSharedPtr const& rootPtr = g_viewState->getScene()->getRootNode().staticCast<dp::sg::core::Group>(); DP_ASSERT( rootPtr ); // add own lights to the root node dp::math::Vec3f firstLightPos = g_viewState->getCamera()->getPosition(); for( size_t i = 0; i < g_numLights; ++i ) { g_lightSources[i] = dp::sg::core::createStandardPointLight( firstLightPos + dp::math::Vec3f( (float)2*i, 0.0f, 0.0f ) ); rootPtr->addChild( g_lightSources[i] ); } } for( size_t i = 0; i < g_numLights; ++i ) { g_lightSources[i]->setEnabled( !!( counter & (1i64 << i) ) ); } }
bool saveScene( std::string const& filename, dp::sg::ui::ViewStateSharedPtr const& viewState, dp::util::PlugInCallback *callback ) { bool result = false; // define a unique plug-interface ID for SceneLoader const dp::util::UPITID PITID_SCENE_SAVER(UPITID_SCENE_SAVER, UPITID_VERSION); vector<string> searchPaths; searchPaths.push_back( dp::util::getCurrentPath() ); std::string modulePath = dp::util::getModulePath(); if ( std::find( searchPaths.begin(), searchPaths.end(), modulePath ) == searchPaths.end() ) { searchPaths.push_back( modulePath ); } #if defined(DP_OS_WINDOWS) modulePath = dp::util::getModulePath( reinterpret_cast<HMODULE>(&__ImageBase) ); if ( std::find( searchPaths.begin(), searchPaths.end(), modulePath ) == searchPaths.end() ) { searchPaths.push_back( modulePath ); } #endif dp::util::UPIID piid = dp::util::UPIID(dp::util::getFileExtension( filename ).c_str(), PITID_SCENE_SAVER); dp::util::PlugIn * plug; if ( getInterface( searchPaths, piid, plug ) ) { SceneSaver *ss = reinterpret_cast<SceneSaver *>(plug); try { dp::sg::core::SceneSharedPtr scene( viewState->getScene() ); // DAR HACK Change SceneSaver interface later. result = ss->save( scene, viewState, filename ); } catch(...) // catch all others { } } return result; }
void SceneRendererPipeline::doRenderTonemap(dp::sg::ui::ViewStateSharedPtr const& viewState, dp::ui::RenderTargetSharedPtr const& renderTarget) { dp::gl::RenderTargetSharedPtr const & renderTargetGL = renderTarget.inplaceCast<dp::gl::RenderTarget>(); dp::gl::TargetBufferMask clearMask = renderTargetGL->getClearMask(); // Match the size of the tonemapFBO to the destination renderTarget. unsigned int width; unsigned int height; renderTarget->getSize(width, height); m_tonemapFBO->setSize(width, height); // Call the current scene renderer and render the whole scene into the main render target (tonemapFBO). DP_ASSERT( viewState->getTraversalMask() == ~0 ); // This renders only one eye even if the renderTarget is stereoscopic. // Important: The m_sceneRenderer holds a NOP StereoViewStateProvider to use the already adjusted stereo ViewState camera! m_sceneRenderer->render(viewState, m_tonemapFBO, renderTarget->getStereoTarget()); if ( m_tonemapperValuesChanged ) { // Set the tonemapper parameters: const dp::sg::core::ParameterGroupDataSharedPtr& parameterGroupData = m_tonemapperData->findParameterGroupData( std::string( "tonemapParameters" ) ); DP_ASSERT( parameterGroupData ); DP_VERIFY( parameterGroupData->setParameter( "invGamma", 1.0f / m_tonemapperValues.gamma ) ); DP_VERIFY( parameterGroupData->setParameter( "invWhitePoint", m_tonemapperValues.brightness / m_tonemapperValues.whitePoint) ); DP_VERIFY( parameterGroupData->setParameter( "saturation", m_tonemapperValues.saturation ) ); DP_VERIFY( parameterGroupData->setParameter( "crushBlacks", m_tonemapperValues.crushBlacks + m_tonemapperValues.crushBlacks + 1.0f) ); // Note, the default if the shader variable crushBlacks is 1.0! DP_VERIFY( parameterGroupData->setParameter( "burnHighlights", m_tonemapperValues.burnHighlights ) ); m_tonemapperValuesChanged = false; } // No need to clear anything. This tonemapping pass just copies pixels and ignores depth. renderTargetGL->setClearMask( 0 ); m_tonemapper->render(); renderTargetGL->setClearMask( clearMask ); }
int runApp( options::variables_map const& opts ) { // Create renderer std::string cullingEngine = opts["cullingengine"].as<std::string>(); dp::culling::Mode cullingMode = dp::culling::Mode::AUTO; if ( cullingEngine == "cpu" ) { cullingMode = dp::culling::Mode::CPU; } else if ( cullingEngine == "gl_compute" ) { cullingMode = dp::culling::Mode::OPENGL_COMPUTE; } else if ( cullingEngine == "cuda" ) { cullingMode = dp::culling::Mode::CUDA; } else if ( cullingEngine != "auto" ) { std::cerr << "unknown culling engine, abort" << std::endl; return -1; } CFRPipelineSharedPtr renderer = CFRPipeline::create ( opts["renderengine"].as<std::string>().c_str() , getShaderManager( opts["shadermanager"].as<std::string>() ) , cullingMode ); //renderer->setCullingEnabled( opts["culling"].as<bool>() ); dp::sg::ui::ViewStateSharedPtr viewStateHandle = loadScene( opts["filename"].as<std::string>() ); g_viewState = viewStateHandle; if ( opts.count("replace") ) { // process replacements std::vector< std::string> replacementStrings = opts["replace"].as< std::vector<std::string > >(); dp::sg::algorithm::ReplacementMapNames replacements; for ( std::vector<std::string>::iterator it = replacementStrings.begin(); it != replacementStrings.end(); ++it ) { size_t equalChar = it->find_first_of(':'); if ( equalChar != std::string::npos && equalChar < it->size() - 1) { std::string str1 = it->substr( 0, equalChar ); std::string str2 = it->substr( equalChar + 1, it->size() - equalChar - 1); replacements[str1] = str2; } else { std::cerr << "invalid replacement token: " << *it << std::endl; } } dp::sg::algorithm::replacePipelineData( viewStateHandle->getScene(), replacements ); } if ( !opts["statistics"].empty() ) { showStatistics( viewStateHandle ); } dp::sg::ui::setupDefaultViewState( viewStateHandle ); if ( !opts["combineVertexAttributes"].empty() ) { combineVertexAttributes( viewStateHandle ); } { // Replace MatrixCamera by PerspectiveCamera to get all manipulator features if ( viewStateHandle->getCamera()->getObjectCode() == dp::sg::core::ObjectCode::MATRIX_CAMERA ) { dp::sg::core::PerspectiveCameraSharedPtr perspectiveCamera = dp::sg::core::PerspectiveCamera::create(); perspectiveCamera->setOrientation(viewStateHandle->getCamera()->getOrientation()); perspectiveCamera->setDirection((viewStateHandle->getCamera()->getDirection())); perspectiveCamera->setPosition(viewStateHandle->getCamera()->getPosition()); viewStateHandle->setAutoClipPlanes(true); viewStateHandle->setCamera(perspectiveCamera); } } if ( !opts["headlight"].empty() ) { // TODO is this still a bug? // Bug 914976 containsLight() doesn't find lights in the scene. Force adding the headlight anyway when the user specified it. if ( viewStateHandle /* && viewStateHandle->getScene() && !SceneLock( viewStateHandle->getScene() )->containsLight() */ && viewStateHandle->getCamera() && ( viewStateHandle->getCamera()->getNumberOfHeadLights() == 0 ) ) { // Use the defaults! Note that LightSource ambientColor is black. viewStateHandle->getCamera()->addHeadLight( dp::sg::core::createStandardPointLight() ); } } // Setup default OpenGL format descriptor // We need to create a default format first to be able to check if a stereo pixelformat is available later. // (An unfortunate RenderContextFormat.isAvailable() interface due to Linux.) dp::gl::RenderContextFormat format; // create a widget which shows the scene //dp::sg::ui::glut::SceneRendererWidget w( format ); GLUTMinimalCFR w; // TODO format is not yet supported #if 0 if (stereo) { format.setStereo( stereo ); if ( !w.setFormat( format ) ) // This automatically checks if the format is available. { std::cout << "Warning: No stereo pixelformat available." << std::endl; } } #endif viewStateHandle->setAutoClipPlanes( opts["autoclipplanes"].as<bool>() ); w.setViewState( viewStateHandle ); w.setSceneRenderer( renderer ); //always on if ( !opts["continuous"].empty() ) { w.setContinuousUpdate( true ); w.setShowFrameRate( true ); } if( opts["frames"].as<int>() != -1 ) { w.setNumberOfFrames( opts["frames"].as<int>() ); } w.setDuration( opts["duration"].as<double>() ); w.setWindowSize( 1280, 720 ); //w.show(); // Keep only once reference to the renderer in the widget. This is necessary since the OpenGL resources // used by the renderer must be deleted before the window gets destroyed. renderer.reset(); g_viewState->getCamera()->setPosition(dp::math::Vec3f(0.0f, 0.0f, 5.0f)); setLights(); glutMainLoop(); return w.getExitCode(); }
void SceneTree::updateObjectTree( dp::sg::ui::ViewStateSharedPtr const& vs ) { // // first step: update node-local information // // update dirty object hints & masks { ObjectObserver::NewCacheData cd; m_objectObserver->popNewCacheData( cd ); ObjectObserver::NewCacheData::const_iterator it, it_end = cd.end(); for( it=cd.begin(); it!=it_end; ++it ) { ObjectTreeNode& node = m_objectTree[ it->first ]; node.m_localHints = it->second.m_hints; node.m_localMask = it->second.m_mask; m_objectTree.markDirty( it->first, ObjectTreeNode::DEFAULT_DIRTY ); } } // update dirty switch information ObjectTreeIndexSet dirtySwitches; m_switchObserver->popDirtySwitches( dirtySwitches ); if( !dirtySwitches.empty() ) { ObjectTreeIndexSet::iterator it, it_end = dirtySwitches.end(); for( it=dirtySwitches.begin(); it!=it_end; ++it ) { ObjectTreeIndex index = *it; SwitchWeakPtr swp = m_objectTree.m_switchNodes[ index ]; DP_ASSERT( swp ); ObjectTreeIndex childIndex = m_objectTree[index].m_firstChild; // counter for the i-th child size_t i = 0; while( childIndex != ~0 ) { ObjectTreeNode& childNode = m_objectTree[childIndex]; DP_ASSERT( childNode.m_parentIndex == index ); bool newActive = swp->isActive( checked_cast<unsigned int>(i) ); if ( childNode.m_localActive != newActive ) { childNode.m_localActive = newActive; m_objectTree.markDirty( childIndex, ObjectTreeNode::DEFAULT_DIRTY ); } childIndex = childNode.m_nextSibling; ++i; } } } // update all lods if( !m_objectTree.m_LODs.empty() ) { float scaleFactor = vs->getLODRangeScale(); const Mat44f& worldToView = vs->getCamera()->getWorldToViewMatrix(); std::map< ObjectTreeIndex, LODWeakPtr >::iterator it, it_end = m_objectTree.m_LODs.end(); for( it = m_objectTree.m_LODs.begin(); it != it_end; ++it ) { ObjectTreeIndex index = it->first; const ObjectTreeNode& node = m_objectTree[ index ]; const Mat44f modelToWorld = getTransformMatrix( node.m_transformIndex ); const Mat44f modelToView = modelToWorld * worldToView; ObjectTreeIndex activeIndex = it->second->getLODToUse( modelToView, scaleFactor ); ObjectTreeIndex childIndex = m_objectTree[index].m_firstChild; // counter for the i-th child size_t i = 0; while( childIndex != ~0 ) { ObjectTreeNode& childNode = m_objectTree[childIndex]; DP_ASSERT( childNode.m_parentIndex == index ); bool newActive = activeIndex == i; if ( childNode.m_localActive != newActive ) { childNode.m_localActive = newActive; m_objectTree.markDirty( childIndex, ObjectTreeNode::DEFAULT_DIRTY ); } childIndex = childNode.m_nextSibling; ++i; } } } // // second step: update resulting node-world information // UpdateObjectVisitor objectVisitor( m_objectTree, this ); PreOrderTreeTraverser<ObjectTree, UpdateObjectVisitor> objectTraverser; objectTraverser.processDirtyList( m_objectTree, objectVisitor, ObjectTreeNode::DEFAULT_DIRTY ); m_objectTree.m_dirtyObjects.clear(); }
void SceneTree::updateTransformTree( dp::sg::ui::ViewStateSharedPtr const& vs ) { // // first step: update node local information // // update dirty transforms from transform observer { const TransformObserver::DirtyPayloads& cd = m_transformObserver->getDirtyPayloads(); TransformObserver::DirtyPayloads::const_iterator it, it_end = cd.end(); for( it = cd.begin(); it != it_end; ++it ) { TransformTreeIndex index = (*it)->m_index; TransformTreeNode& node = m_transformTree[index]; DP_ASSERT( node.m_transform != nullptr ); const Trafo& t = node.m_transform->getTrafo(); node.m_localMatrix = t.getMatrix(); const Vec3f& s( t.getScaling() ); node.setLocalBits( TransformTreeNode::ISMIRRORTRANSFORM, s[0]*s[1]*s[2] < 0.0f ); m_transformTree.markDirty( index, TransformTreeNode::DEFAULT_DIRTY ); // mark the transform's corresponding object tree node's bounding volume dirty DP_ASSERT( node.m_objectTreeIndex != ~0 ); (*it)->m_dirty = false; } m_transformObserver->clearDirtyPayloads(); } // update dynamic transforms { TransformTreeIndexSet::const_iterator it, it_end = m_dynamicTransformIndices.end(); for( it=m_dynamicTransformIndices.begin(); it!=it_end; ++it ) { TransformTreeIndex index = *it; TransformTreeNode& node = m_transformTree[index]; if( node.m_transform ) { Trafo t = node.m_transform->getTrafo(); node.m_localMatrix = t.getMatrix(); const Vec3f& s( t.getScaling() ); node.setLocalBits( TransformTreeNode::ISMIRRORTRANSFORM, s[0]*s[1]*s[2] < 0.0f ); } m_transformTree.markDirty( index, TransformTreeNode::DEFAULT_DIRTY ); } } // // second step: update resulting node-world information // m_changedTransforms.clear(); UpdateTransformVisitor visitor( m_transformTree, *this, vs->getCamera(), m_changedTransforms ); PreOrderTreeTraverser<TransformTree, UpdateTransformVisitor> traverser; traverser.processDirtyList( m_transformTree, visitor, TransformTreeNode::DEFAULT_DIRTY); m_transformTree.m_dirtyObjects.clear(); }
void SceneRendererPipeline::doRenderHighlight(dp::sg::ui::ViewStateSharedPtr const& viewState, dp::ui::RenderTargetSharedPtr const& renderTarget) { // only call this if objects need to be rendered highlighted DP_ASSERT(m_highlighting); // Highlight pass: // Match the size of the highlightFBO to the destination renderTarget. unsigned int width; unsigned int height; renderTarget->getSize(width, height); m_highlightFBO->setSize(width, height); unsigned int originalTraversalMask = viewState->getTraversalMask(); viewState->setTraversalMask(2); // Render only the highlighted objects. glPushAttrib( GL_STENCIL_BUFFER_BIT ); // If an object is highlighted, render the highlighted object into the stencil buffer of the FBO. // Setup the proper stencil state. // Write a 1 for every rendered fragment into the stencil buffer glStencilFunc(GL_NEVER, 1, ~0); glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP); glEnable(GL_STENCIL_TEST); // This is always using a SceneRendererGL2 to render the highlighted objects. m_highlightFBO->setClearMask( dp::gl::TBM_COLOR_BUFFER | dp::gl::TBM_DEPTH_BUFFER | dp::gl::TBM_STENCIL_BUFFER); // Clear all. // A SceneRenderer always uses the scene background color to clear. Temporarily change it to black here. dp::math::Vec4f backgroundColor = viewState->getScene()->getBackColor(); viewState->getScene()->setBackColor( dp::math::Vec4f(0.0f, 0.0f, 0.0f, 0.0f) ); m_sceneRendererHighlight->render(viewState, m_highlightFBO); viewState->getScene()->setBackColor(backgroundColor); viewState->setTraversalMask(originalTraversalMask); // Reset the traversal mask. // Highlight post-processing: // Migrate the stencil bit contents as white color into the texture rectangle. m_highlightFBO->setClearMask( dp::gl::TBM_COLOR_BUFFER ); // Do not clear the stencil! Don't care for depth. // set the stencil as needed for the stencil to color pass glStencilFunc( GL_EQUAL, 1, ~0 ); glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP ); m_rendererStencilToColor->render(); glPopAttrib(); // Render the outline around the highlighted object onto the main renderTarget (framebuffer). dp::gl::RenderTargetSharedPtr const & renderTargetGL = renderTarget.inplaceCast<dp::gl::RenderTarget>(); dp::gl::TargetBufferMask clearMask = renderTargetGL->getClearMask(); // keep the following render call from clearing the previous rendered content renderTargetGL->setClearMask( 0 ); m_rendererHighlight->render(); // restore the clear mask renderTargetGL->setClearMask( clearMask ); }