From 302c58fc93d611594f8585cde557309b590b0490 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Thu, 21 Jul 2005 19:27:19 +0000 Subject: [PATCH] Implemented the beginings of the osgProducer::GraphicsContexImplementation. Added options into osgprerender for controlling how to do the pre rendering i.e. --fbo, --pbuffer, --fb --window, and also added the option for controlling the window size with --width and --height. --- examples/osgpbuffer/osgpbuffer.cpp | 14 +- examples/osgprerender/osgprerender.cpp | 232 +++++++++++++------------ include/osg/CameraNode | 3 +- include/osg/GraphicsContext | 11 +- include/osgProducer/OsgCameraGroup | 11 ++ include/osgUtil/RenderToTextureStage | 6 + src/osgProducer/GNUmakefile | 1 + src/osgProducer/OsgCameraGroup.cpp | 13 ++ src/osgUtil/CullVisitor.cpp | 78 +++++++++ src/osgUtil/RenderToTextureStage.cpp | 39 ++++- 10 files changed, 277 insertions(+), 131 deletions(-) diff --git a/examples/osgpbuffer/osgpbuffer.cpp b/examples/osgpbuffer/osgpbuffer.cpp index b1c4cf2ee..ee2e8a4fe 100644 --- a/examples/osgpbuffer/osgpbuffer.cpp +++ b/examples/osgpbuffer/osgpbuffer.cpp @@ -49,8 +49,6 @@ class PBufferTexture2D : public osg::Texture2D glTexImage2D( GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, 0 ); textureObject->setAllocated(true); - - std::cout<<"Created texture"<bindPBufferToTexture( Producer::RenderSurface::FrontBuffer ); - } - else - { - std::cout<<"..."<bindPBufferToTexture( Producer::RenderSurface::FrontBuffer ); ++frameNum; @@ -453,7 +443,7 @@ int main( int argc, char **argv ) } } -printf( "PBuffer window: 0x%x\n", pbuffer->getWindow() ); + printf( "PBuffer window: 0x%x\n", pbuffer->getWindow() ); viewer.getCamera(0)->setClearColor( 0.1f,0.9f,0.3f,1.0f ); diff --git a/examples/osgprerender/osgprerender.cpp b/examples/osgprerender/osgprerender.cpp index d57941127..a44e1c89f 100644 --- a/examples/osgprerender/osgprerender.cpp +++ b/examples/osgprerender/osgprerender.cpp @@ -107,136 +107,139 @@ class MyGeometryCallback : }; -osg::Node* createPreRenderSubGraph(osg::Node* subgraph) +osg::Node* createPreRenderSubGraph(osg::Node* subgraph, unsigned tex_width, unsigned tex_height, osg::CameraNode::RenderTargetImplementation renderImplementation) { if (!subgraph) return 0; - - // create the quad to visualize. - osg::Geometry* polyGeom = new osg::Geometry(); - polyGeom->setSupportsDisplayList(false); - - osg::Vec3 origin(0.0f,0.0f,0.0f); - osg::Vec3 xAxis(1.0f,0.0f,0.0f); - osg::Vec3 yAxis(0.0f,0.0f,1.0f); - osg::Vec3 zAxis(0.0f,-1.0f,0.0f); - float height = 100.0f; - float width = 200.0f; - int noSteps = 20; - - osg::Vec3Array* vertices = new osg::Vec3Array; - osg::Vec3 bottom = origin; - osg::Vec3 top = origin; top.z()+= height; - osg::Vec3 dv = xAxis*(width/((float)(noSteps-1))); - - osg::Vec2Array* texcoords = new osg::Vec2Array; - osg::Vec2 bottom_texcoord(0.0f,0.0f); - osg::Vec2 top_texcoord(0.0f,1.0f); - osg::Vec2 dv_texcoord(1.0f/(float)(noSteps-1),0.0f); - - for(int i=0;ipush_back(top); - vertices->push_back(bottom); - top+=dv; - bottom+=dv; - - texcoords->push_back(top_texcoord); - texcoords->push_back(bottom_texcoord); - top_texcoord+=dv_texcoord; - bottom_texcoord+=dv_texcoord; - } - - - // pass the created vertex array to the points geometry object. - polyGeom->setVertexArray(vertices); - - polyGeom->setTexCoordArray(0,texcoords); - - - osg::Vec4Array* colors = new osg::Vec4Array; - colors->push_back(osg::Vec4(1.0f,1.0f,1.0f,1.0f)); - polyGeom->setColorArray(colors); - polyGeom->setColorBinding(osg::Geometry::BIND_OVERALL); - - polyGeom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUAD_STRIP,0,vertices->size())); - - - - unsigned int tex_width = 2048; - unsigned int tex_height = 2048; - - - // new we need to add the texture to the Drawable, we do so by creating a - // StateSet to contain the Texture StateAttribute. - osg::StateSet* stateset = new osg::StateSet; + // create a group to contain the flag and the pre rendering camera. + osg::Group* parent = new osg::Group; + // texture to render to and to use for rendering of flag. osg::Texture2D* texture = new osg::Texture2D; texture->setTextureSize(tex_width, tex_height); texture->setInternalFormat(GL_RGBA); texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR); texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR); - stateset->setTextureAttributeAndModes(0, texture,osg::StateAttribute::ON); - polyGeom->setStateSet(stateset); + // first create the geometry of the flag of which to view. + { + // create the to visualize. + osg::Geometry* polyGeom = new osg::Geometry(); - polyGeom->setUpdateCallback(new MyGeometryCallback(origin,xAxis,yAxis,zAxis,1.0,1.0/width,0.2f)); + polyGeom->setSupportsDisplayList(false); - osg::Geode* geode = new osg::Geode(); - geode->addDrawable(polyGeom); + osg::Vec3 origin(0.0f,0.0f,0.0f); + osg::Vec3 xAxis(1.0f,0.0f,0.0f); + osg::Vec3 yAxis(0.0f,0.0f,1.0f); + osg::Vec3 zAxis(0.0f,-1.0f,0.0f); + float height = 100.0f; + float width = 200.0f; + int noSteps = 20; + + osg::Vec3Array* vertices = new osg::Vec3Array; + osg::Vec3 bottom = origin; + osg::Vec3 top = origin; top.z()+= height; + osg::Vec3 dv = xAxis*(width/((float)(noSteps-1))); + + osg::Vec2Array* texcoords = new osg::Vec2Array; + osg::Vec2 bottom_texcoord(0.0f,0.0f); + osg::Vec2 top_texcoord(0.0f,1.0f); + osg::Vec2 dv_texcoord(1.0f/(float)(noSteps-1),0.0f); + + for(int i=0;ipush_back(top); + vertices->push_back(bottom); + top+=dv; + bottom+=dv; + + texcoords->push_back(top_texcoord); + texcoords->push_back(bottom_texcoord); + top_texcoord+=dv_texcoord; + bottom_texcoord+=dv_texcoord; + } - osg::CameraNode* camera = new osg::CameraNode; - - // set up the background color and clear mask. - camera->setClearColor(osg::Vec4(0.1f,0.1f,0.3f,1.0f)); - camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + // pass the created vertex array to the points geometry object. + polyGeom->setVertexArray(vertices); + + polyGeom->setTexCoordArray(0,texcoords); + + + osg::Vec4Array* colors = new osg::Vec4Array; + colors->push_back(osg::Vec4(1.0f,1.0f,1.0f,1.0f)); + polyGeom->setColorArray(colors); + polyGeom->setColorBinding(osg::Geometry::BIND_OVERALL); + + polyGeom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUAD_STRIP,0,vertices->size())); + + // new we need to add the texture to the Drawable, we do so by creating a + // StateSet to contain the Texture StateAttribute. + osg::StateSet* stateset = new osg::StateSet; + + stateset->setTextureAttributeAndModes(0, texture,osg::StateAttribute::ON); + + polyGeom->setStateSet(stateset); + + polyGeom->setUpdateCallback(new MyGeometryCallback(origin,xAxis,yAxis,zAxis,1.0,1.0/width,0.2f)); + + osg::Geode* geode = new osg::Geode(); + geode->addDrawable(polyGeom); + + parent->addChild(geode); - const osg::BoundingSphere& bs = subgraph->getBound(); - if (!bs.valid()) - { - return subgraph; } - float znear = 1.0f*bs.radius(); - float zfar = 3.0f*bs.radius(); - // 2:1 aspect ratio as per flag geomtry below. - float proj_top = 0.25f*znear; - float proj_right = 0.5f*znear; + // then create the camera node to do the render to texture + { + osg::CameraNode* camera = new osg::CameraNode; - znear *= 0.9f; - zfar *= 1.1f; + // set up the background color and clear mask. + camera->setClearColor(osg::Vec4(0.1f,0.1f,0.3f,1.0f)); + camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - // set up projection. - camera->setProjectionMatrixAsFrustum(-proj_right,proj_right,-proj_top,proj_top,znear,zfar); + const osg::BoundingSphere& bs = subgraph->getBound(); + if (!bs.valid()) + { + return subgraph; + } - // set view - camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF); - camera->setViewMatrixAsLookAt(bs.center()-osg::Vec3(0.0f,2.0f,0.0f)*bs.radius(),bs.center(),osg::Vec3(0.0f,0.0f,1.0f)); + float znear = 1.0f*bs.radius(); + float zfar = 3.0f*bs.radius(); - // set viewport - camera->setViewport(0,0,tex_width,tex_height); - - // set the camera to render before the main camera. - camera->setRenderOrder(osg::CameraNode::PRE_RENDER); - - // tell the camera to use OpenGL frame buffer object where supported. - camera->setRenderTargetImplmentation(osg::CameraNode::FRAME_BUFFER_OBJECT); - - // attach the texture and use it as the color buffer. - camera->attach(osg::CameraNode::COLOR_BUFFER, texture); + // 2:1 aspect ratio as per flag geomtry below. + float proj_top = 0.25f*znear; + float proj_right = 0.5f*znear; - // add subgraph to render - camera->addChild(subgraph); - - - // create a group to contain the flag and the pre rendering camera. - osg::Group* parent = new osg::Group; - - parent->addChild(camera); - parent->addChild(geode); + znear *= 0.9f; + zfar *= 1.1f; + // set up projection. + camera->setProjectionMatrixAsFrustum(-proj_right,proj_right,-proj_top,proj_top,znear,zfar); + + // set view + camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF); + camera->setViewMatrixAsLookAt(bs.center()-osg::Vec3(0.0f,2.0f,0.0f)*bs.radius(),bs.center(),osg::Vec3(0.0f,0.0f,1.0f)); + + // set viewport + camera->setViewport(0,0,tex_width,tex_height); + + // set the camera to render before the main camera. + camera->setRenderOrder(osg::CameraNode::PRE_RENDER); + + // tell the camera to use OpenGL frame buffer object where supported. + camera->setRenderTargetImplmentation(renderImplementation); + + // attach the texture and use it as the color buffer. + camera->attach(osg::CameraNode::COLOR_BUFFER, texture); + + // add subgraph to render + camera->addChild(subgraph); + + parent->addChild(camera); + + } return parent; } @@ -267,6 +270,19 @@ int main( int argc, char **argv ) return 1; } + unsigned tex_width = 1024; + unsigned tex_height = 512; + while (arguments.read("--width", tex_width)) {} + while (arguments.read("--height", tex_height)) {} + + osg::CameraNode::RenderTargetImplementation renderImplementation = osg::CameraNode::FRAME_BUFFER_OBJECT; + + while (arguments.read("--fbo")) { renderImplementation = osg::CameraNode::FRAME_BUFFER_OBJECT; } + while (arguments.read("--pbuffer")) { renderImplementation = osg::CameraNode::PIXEL_BUFFER; } + while (arguments.read("--fb")) { renderImplementation = osg::CameraNode::FRAME_BUFFER; } + while (arguments.read("--window")) { renderImplementation = osg::CameraNode::SEPERATE_WINDOW; } + + // any option left unread are converted into errors to write out later. arguments.reportRemainingOptionsAsUnrecognized(); @@ -288,7 +304,6 @@ int main( int argc, char **argv ) osg::Node* loadedModel = osgDB::readNodeFiles(arguments); if (!loadedModel) { -// write_usage(osg::notify(osg::NOTICE),argv[0]); return 1; } @@ -300,8 +315,7 @@ int main( int argc, char **argv ) loadedModelTransform->setUpdateCallback(nc); osg::Group* rootNode = new osg::Group(); -// rootNode->addChild(loadedModelTransform); - rootNode->addChild(createPreRenderSubGraph(loadedModelTransform)); + rootNode->addChild(createPreRenderSubGraph(loadedModelTransform,tex_width,tex_height, renderImplementation)); // add model to the viewer. diff --git a/include/osg/CameraNode b/include/osg/CameraNode index 304633cb5..dd9eb968b 100644 --- a/include/osg/CameraNode +++ b/include/osg/CameraNode @@ -184,7 +184,8 @@ class OSG_EXPORT CameraNode : public Transform, public CullSettings { FRAME_BUFFER_OBJECT, PIXEL_BUFFER, - FRAME_BUFFER + FRAME_BUFFER, + SEPERATE_WINDOW }; void setRenderTargetImplmentation(RenderTargetImplementation impl) { _renderTargetImplementation = impl; } diff --git a/include/osg/GraphicsContext b/include/osg/GraphicsContext index 1d5ecfe8f..f79e3892c 100644 --- a/include/osg/GraphicsContext +++ b/include/osg/GraphicsContext @@ -120,18 +120,21 @@ class OSG_EXPORT GraphicsContext : public Referenced /** Return true if the current thread has this OpenGL graphics context.*/ inline bool isCurrent() const { return _threadOfLastMakeCurrent == OpenThreads::Thread::CurrentThread(); } + /** Release the graphics context.*/ + virtual void release() = 0; + /** Make this graphics context current.*/ virtual void makeCurrent() = 0; /** Make this graphics context current with specified read context.*/ - virtual void makeCurrentContext(GraphicsContext* readContext) = 0; - - /** Release the graphics context.*/ - virtual void release() = 0; + virtual void makeContextCurrent(GraphicsContext* readContext) = 0; /** Bind the graphics context to associated texture.*/ virtual void bindPBufferToTexture(GLenum buffer) = 0; + /** swap the front and back buffers.*/ + virtual void swapBuffers() = 0; + protected: GraphicsContext(); diff --git a/include/osgProducer/OsgCameraGroup b/include/osgProducer/OsgCameraGroup index 79474b8ca..ff852a21b 100644 --- a/include/osgProducer/OsgCameraGroup +++ b/include/osgProducer/OsgCameraGroup @@ -28,6 +28,7 @@ #include #include +#include namespace osgProducer { @@ -55,6 +56,15 @@ class OSGPRODUCER_EXPORT OsgCameraGroup : public Producer::CameraGroup const osg::ApplicationUsage* getApplicationUsage() const { return _applicationUsage; } + typedef std::vector< osg::ref_ptr > GraphicsContextList; + + void setGraphicsContextList(GraphicsContextList& gcList) { _gcList = gcList; } + + GraphicsContextList& getGraphicsContextList() { return _gcList;} + + const GraphicsContextList& getGraphicsContextList() const { return _gcList;} + + typedef std::vector < osg::ref_ptr > SceneHandlerList; SceneHandlerList& getSceneHandlerList() { return _shvec;} @@ -212,6 +222,7 @@ class OSGPRODUCER_EXPORT OsgCameraGroup : public Producer::CameraGroup unsigned int _realizeSceneViewOptions; + GraphicsContextList _gcList; SceneHandlerList _shvec; osg::ref_ptr _realizeCallback; diff --git a/include/osgUtil/RenderToTextureStage b/include/osgUtil/RenderToTextureStage index 49cec51ff..9cc1ac1d6 100644 --- a/include/osgUtil/RenderToTextureStage +++ b/include/osgUtil/RenderToTextureStage @@ -16,6 +16,7 @@ #include #include +#include #include @@ -56,6 +57,10 @@ class OSGUTIL_EXPORT RenderToTextureStage : public RenderStage void setFrameBufferObject(osg::FrameBufferObject* fbo) { _fbo = fbo; } osg::FrameBufferObject* getFrameBufferObject() { return _fbo.get(); } const osg::FrameBufferObject* getFrameBufferObject() const { return _fbo.get(); } + + void setGraphicsContext(osg::GraphicsContext* context) { _graphicsContext = context; } + osg::GraphicsContext* getGraphicsContext() { return _graphicsContext.get(); } + const osg::GraphicsContext* getGraphicsContext() const { return _graphicsContext.get(); } virtual void draw(osg::State& state,RenderLeaf*& previous); @@ -72,6 +77,7 @@ class OSGUTIL_EXPORT RenderToTextureStage : public RenderStage GLenum _imageReadPixelDataType; osg::ref_ptr _fbo; + osg::ref_ptr _graphicsContext; }; diff --git a/src/osgProducer/GNUmakefile b/src/osgProducer/GNUmakefile index 2149c86d4..77e307dd4 100644 --- a/src/osgProducer/GNUmakefile +++ b/src/osgProducer/GNUmakefile @@ -4,6 +4,7 @@ include $(TOPDIR)/Make/makedefs CXXFILES =\ EventAdapter.cpp\ KeyboardMouseCallback.cpp\ + GraphicsContextImplementation.cpp\ OsgCameraGroup.cpp\ OsgSceneHandler.cpp\ ViewerEventHandler.cpp\ diff --git a/src/osgProducer/OsgCameraGroup.cpp b/src/osgProducer/OsgCameraGroup.cpp index af439658c..62d32f373 100644 --- a/src/osgProducer/OsgCameraGroup.cpp +++ b/src/osgProducer/OsgCameraGroup.cpp @@ -511,6 +511,19 @@ bool OsgCameraGroup::realize() } } + // now set up GraphicsContext wrappers for each of the render surfaces + // to all core OSG classes to keep track of the graphics context. + for(RenderSurfaceStateMap::iterator ritr = _renderSurfaceStateMap.begin(); + ritr != _renderSurfaceStateMap.end(); + ++ritr) + { + Producer::RenderSurface* rs = ritr->first; + osg::State* state = ritr->second; + GraphicsContextImplementation* gc = new GraphicsContextImplementation(rs); + gc->setState(state); + state->setGraphicsContext(gc); + _gcList.push_back(gc); + } if( _global_stateset == NULL && _shvec.size() > 0 ) { diff --git a/src/osgUtil/CullVisitor.cpp b/src/osgUtil/CullVisitor.cpp index d07b7248f..898f090e5 100644 --- a/src/osgUtil/CullVisitor.cpp +++ b/src/osgUtil/CullVisitor.cpp @@ -1217,6 +1217,84 @@ void CullVisitor::apply(osg::CameraNode& camera) } } } + else if (camera.getRenderTargetImplmentation()==osg::CameraNode::PIXEL_BUFFER || + camera.getRenderTargetImplmentation()==osg::CameraNode::SEPERATE_WINDOW ) + { + osg::ref_ptr context = rtts->getGraphicsContext(); + if (!context) + { + // set up the traits of the graphics context that we want + osg::ref_ptr traits = new osg::GraphicsContext::Traits; + + traits->_width = viewport->width(); + traits->_height = viewport->height(); + traits->_pbuffer = (camera.getRenderTargetImplmentation()==osg::CameraNode::PIXEL_BUFFER); + traits->_windowDecoration = (camera.getRenderTargetImplmentation()==osg::CameraNode::SEPERATE_WINDOW); + + + bool colorAttached = false; + bool depthAttached = false; + bool stencilAttached = false; + for(osg::CameraNode::BufferAttachmentMap::iterator itr = bufferAttachements.begin(); + itr != bufferAttachements.end(); + ++itr) + { + + osg::CameraNode::BufferComponent buffer = itr->first; + osg::CameraNode::Attachment& attachment = itr->second; + switch(buffer) + { + case(osg::CameraNode::DEPTH_BUFFER): + { + traits->_depth = 24; + depthAttached = true; + break; + } + case(osg::CameraNode::STENCIL_BUFFER): + { + traits->_stencil = 8; + stencilAttached = true; + break; + } + default: + { + traits->_red = 8; + traits->_green = 8; + traits->_blue = 8; + traits->_alpha = 0; // ??? need to look at attachment, just do quick and dirty right now. + colorAttached = true; + break; + } + + } + } + + if (!depthAttached) + { + traits->_depth = 24; + } + + if (!colorAttached) + { + traits->_red = 8; + traits->_green = 8; + traits->_blue = 8; + traits->_alpha = 0; // ??? + } + + // create the graphics context according to these traits. + context = osg::GraphicsContext::createGraphicsContext(traits.get()); + + if (!context) + { + osg::notify(osg::NOTICE)<<"Failed to aquire Graphics Context"<setGraphicsContext(context.get()); + + } + } + } diff --git a/src/osgUtil/RenderToTextureStage.cpp b/src/osgUtil/RenderToTextureStage.cpp index 7b2df4560..d95d0bd05 100644 --- a/src/osgUtil/RenderToTextureStage.cpp +++ b/src/osgUtil/RenderToTextureStage.cpp @@ -40,35 +40,64 @@ void RenderToTextureStage::draw(osg::State& state,RenderLeaf*& previous) //cout << "begining RTTS draw "<x()<<","<< _viewport->y()<<","<< _viewport->width()<<","<< _viewport->height()<getState(); + useContext = _graphicsContext.get(); + useContext->makeCurrent(); + + glDrawBuffer(GL_FRONT); + glReadBuffer(GL_FRONT); + + } + osg::FBOExtensions* fbo_ext = _fbo.valid() ? osg::FBOExtensions::instance(state.getContextID()) : 0; bool fbo_supported = fbo_ext && fbo_ext->isSupported(); if (fbo_supported) { - _fbo->apply(state); + _fbo->apply(*useState); } - - RenderStage::draw(state,previous); + // do the actual rendering of the scene. + RenderStage::draw(*useState,previous); // now copy the rendered image to attached texture. if (_texture.valid() && !fbo_supported) { - //cout << " reading "<x()<<","<< _viewport->y()<<","<< _viewport->width()<<","<< _viewport->height()<makeContextCurrent(useContext); + glReadBuffer(GL_FRONT); + } + + // need to implement texture cube map etc... _texture->copyTexImage2D(state,_viewport->x(),_viewport->y(),_viewport->width(),_viewport->height()); } if (_image.valid()) { _image->readPixels(_viewport->x(),_viewport->y(),_viewport->width(),_viewport->height(),_imageReadPixelFormat,_imageReadPixelDataType); - } if (fbo_supported) { + // switch of the frame buffer object fbo_ext->glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); } + if (callingContext && useContext != callingContext) + { + // restore the graphics context. + callingContext->makeCurrent(); + + glReadBuffer(GL_BACK); + } }