root/OpenSceneGraph/trunk/src/osgVolume/VolumeScene.cpp @ 14044

Revision 14044, 19.9 kB (checked in by robert, 10 days ago)

Added shaders to support experimental shader based displacement mapping technique osgTerrain::ShaderTerrain?.

Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2009 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * OpenSceneGraph Public License for more details.
12*/
13
14#include <osgVolume/VolumeScene>
15#include <osg/Geometry>
16#include <osg/PrimitiveSet>
17#include <osg/Depth>
18#include <osg/Geode>
19#include <osg/ValueObject>
20#include <osg/io_utils>
21#include <osgDB/ReadFile>
22#include <OpenThreads/ScopedLock>
23#include <limits>
24
25using namespace osgVolume;
26
27class RTTCameraCullCallback : public osg::NodeCallback
28{
29    public:
30
31        RTTCameraCullCallback(VolumeScene* vs):
32            _volumeScene(vs) {}
33
34        virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
35        {
36            osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(nv);
37
38            _volumeScene->osg::Group::traverse(*nv);
39
40            node->setUserValue("CalculatedNearPlane",double(cv->getCalculatedNearPlane()));
41            node->setUserValue("CalculatedFarPlane",double(cv->getCalculatedFarPlane()));
42        }
43
44    protected:
45
46        virtual ~RTTCameraCullCallback() {}
47
48        osgVolume::VolumeScene* _volumeScene;
49};
50
51
52VolumeScene::ViewData::ViewData()
53{
54}
55
56void VolumeScene::ViewData::clearTiles()
57{
58    for(Tiles::iterator itr = _tiles.begin();
59        itr != _tiles.end();
60        ++itr)
61    {
62        if (itr->second.valid()) itr->second->active = false;
63    }
64}
65
66void VolumeScene::ViewData::visitTile(VolumeTile* tile)
67{
68}
69
70VolumeScene::VolumeScene()
71{
72}
73
74VolumeScene::VolumeScene(const VolumeScene& vs, const osg::CopyOp& copyop):
75    osg::Group(vs,copyop)
76{
77}
78
79
80VolumeScene::~VolumeScene()
81{
82}
83
84VolumeScene::TileData* VolumeScene::tileVisited(osgUtil::CullVisitor* cv, osgVolume::VolumeTile* tile)
85{
86    osg::ref_ptr<ViewData> viewData;
87
88    {
89        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_viewDataMapMutex);
90        viewData = _viewDataMap[cv];
91    }
92
93    //osg::BoundingBox bb(0.0f,0.0f,0.0f,1.0f,1.0f,1.0f);
94    //cv->updateCalculatedNearFar(*(cv->getModelViewMatrix()),bb);
95
96    if (viewData.valid())
97    {
98        int textureWidth = 512;
99        int textureHeight = 512;
100
101        osg::Viewport* viewport = cv->getCurrentRenderStage()->getViewport();
102        if (viewport)
103        {
104            textureWidth = static_cast<int>(viewport->width());
105            textureHeight = static_cast<int>(viewport->height());
106        }
107
108        osg::ref_ptr<TileData>& tileData = viewData->_tiles[tile];
109        if (!tileData)
110        {
111            tileData = new TileData;
112
113            tileData->depthTexture = new osg::Texture2D;
114            tileData->depthTexture->setTextureSize(textureWidth, textureHeight);
115            tileData->depthTexture->setInternalFormat(GL_DEPTH_COMPONENT);
116            tileData->depthTexture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR);
117            tileData->depthTexture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR);
118            tileData->depthTexture->setWrap(osg::Texture2D::WRAP_S,osg::Texture2D::CLAMP_TO_BORDER);
119            tileData->depthTexture->setWrap(osg::Texture2D::WRAP_T,osg::Texture2D::CLAMP_TO_BORDER);
120            tileData->depthTexture->setBorderColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
121
122            tileData->rttCamera = new osg::Camera;
123            tileData->rttCamera->setName("tileData->rttCamera");
124            tileData->rttCamera->attach(osg::Camera::DEPTH_BUFFER, tileData->depthTexture.get());
125            tileData->rttCamera->setViewport(0,0,textureWidth,textureHeight);
126
127            // clear the depth and colour bufferson each clear.
128            tileData->rttCamera->setClearMask(GL_DEPTH_BUFFER_BIT);
129
130            // set the camera to render before the main camera.
131            tileData->rttCamera->setRenderOrder(osg::Camera::PRE_RENDER);
132
133            // tell the camera to use OpenGL frame buffer object where supported.
134            tileData->rttCamera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
135
136            tileData->rttCamera->setReferenceFrame(osg::Transform::RELATIVE_RF);
137            tileData->rttCamera->setProjectionMatrix(osg::Matrixd::identity());
138            tileData->rttCamera->setViewMatrix(osg::Matrixd::identity());
139
140            tileData->stateset = new osg::StateSet;
141            tileData->stateset->setTextureAttribute(2, tileData->depthTexture.get(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE);
142
143            tileData->texgenUniform = new osg::Uniform("texgen",osg::Matrixf());
144            tileData->stateset->addUniform(tileData->texgenUniform.get());
145        }
146
147        tileData->active = true;
148        tileData->nodePath = cv->getNodePath();
149        tileData->projectionMatrix = cv->getProjectionMatrix();
150        tileData->modelviewMatrix = cv->getModelViewMatrix();
151
152
153        if (tileData->depthTexture.valid())
154        {
155            if (tileData->depthTexture->getTextureWidth()!=textureWidth || tileData->depthTexture->getTextureHeight()!=textureHeight)
156            {
157                OSG_NOTICE<<"Need to change texture size to "<<textureHeight<<", "<<textureWidth<<std::endl;
158                tileData->depthTexture->setTextureSize(textureWidth, textureHeight);
159                tileData->rttCamera->setViewport(0, 0, textureWidth, textureHeight);
160                if (tileData->rttCamera->getRenderingCache())
161                {
162                    tileData->rttCamera->getRenderingCache()->releaseGLObjects(0);
163                }
164            }
165        }
166
167        return tileData.get();
168    }
169    return 0;
170}
171
172VolumeScene::TileData* VolumeScene::getTileData(osgUtil::CullVisitor* cv, osgVolume::VolumeTile* tile)
173{
174    osg::ref_ptr<ViewData> viewData;
175    {
176        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_viewDataMapMutex);
177        viewData = _viewDataMap[cv];
178    }
179
180    if (!viewData) return 0;
181
182    Tiles::iterator itr = viewData->_tiles.find(tile);
183    return (itr != viewData->_tiles.end()) ? itr->second.get() : 0;
184}
185
186void VolumeScene::traverse(osg::NodeVisitor& nv)
187{
188    osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(&nv);
189    if (!cv)
190    {
191        Group::traverse(nv);
192        return;
193    }
194
195    osg::ref_ptr<ViewData> viewData;
196    bool initializeViewData = false;
197    {
198        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_viewDataMapMutex);
199        if (!_viewDataMap[cv])
200        {
201            _viewDataMap[cv] = new ViewData;
202            initializeViewData = true;
203        }
204
205        viewData = _viewDataMap[cv];
206    }
207
208    if (initializeViewData)
209    {
210        OSG_NOTICE<<"Creating ViewData"<<std::endl;
211
212        int textureWidth = 512;
213        int textureHeight = 512;
214
215        osg::Viewport* viewport = cv->getCurrentRenderStage()->getViewport();
216        if (viewport)
217        {
218            textureWidth = static_cast<int>(viewport->width());
219            textureHeight = static_cast<int>(viewport->height());
220        }
221
222        // set up depth texture
223        viewData->_depthTexture = new osg::Texture2D;
224
225        viewData->_depthTexture->setTextureSize(textureWidth, textureHeight);
226        viewData->_depthTexture->setInternalFormat(GL_DEPTH_COMPONENT);
227        viewData->_depthTexture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR);
228        viewData->_depthTexture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR);
229
230        viewData->_depthTexture->setWrap(osg::Texture2D::WRAP_S,osg::Texture2D::CLAMP_TO_BORDER);
231        viewData->_depthTexture->setWrap(osg::Texture2D::WRAP_T,osg::Texture2D::CLAMP_TO_BORDER);
232        viewData->_depthTexture->setBorderColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
233
234        // set up color texture
235        viewData->_colorTexture = new osg::Texture2D;
236
237        viewData->_colorTexture->setTextureSize(textureWidth, textureHeight);
238        viewData->_colorTexture->setInternalFormat(GL_RGBA);
239        viewData->_colorTexture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR);
240        viewData->_colorTexture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR);
241
242        viewData->_colorTexture->setWrap(osg::Texture2D::WRAP_S,osg::Texture2D::CLAMP_TO_EDGE);
243        viewData->_colorTexture->setWrap(osg::Texture2D::WRAP_T,osg::Texture2D::CLAMP_TO_EDGE);
244
245
246        // set up the RTT Camera to capture the main scene to a color and depth texture that can be used in post processing
247        viewData->_rttCamera = new osg::Camera;
248        viewData->_rttCamera->setName("viewData->_rttCamera");
249        viewData->_rttCamera->attach(osg::Camera::DEPTH_BUFFER, viewData->_depthTexture.get());
250        viewData->_rttCamera->attach(osg::Camera::COLOR_BUFFER, viewData->_colorTexture.get());
251        viewData->_rttCamera->setCullCallback(new RTTCameraCullCallback(this));
252        viewData->_rttCamera->setViewport(0,0,textureWidth,textureHeight);
253
254        // clear the depth and colour bufferson each clear.
255        viewData->_rttCamera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
256
257        // set the camera to render before the main camera.
258        viewData->_rttCamera->setRenderOrder(osg::Camera::PRE_RENDER);
259
260        // tell the camera to use OpenGL frame buffer object where supported.
261        viewData->_rttCamera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
262
263
264        viewData->_rttCamera->setReferenceFrame(osg::Transform::RELATIVE_RF);
265        viewData->_rttCamera->setProjectionMatrix(osg::Matrixd::identity());
266        viewData->_rttCamera->setViewMatrix(osg::Matrixd::identity());
267
268        // create mesh for rendering the RTT textures onto the screen
269        osg::ref_ptr<osg::Geode> geode = new osg::Geode;
270        geode->setCullingActive(false);
271
272        viewData->_backdropSubgraph = geode;
273        //geode->addDrawable(osg::createTexturedQuadGeometry(osg::Vec3(-1.0f,-1.0f,-1.0f),osg::Vec3(2.0f,0.0f,-1.0f),osg::Vec3(0.0f,2.0f,-1.0f)));
274
275        viewData->_geometry = new osg::Geometry;
276        geode->addDrawable(viewData->_geometry.get());
277
278        viewData->_geometry->setUseDisplayList(false);
279        viewData->_geometry->setUseVertexBufferObjects(false);
280
281        viewData->_vertices = new osg::Vec3Array(4);
282        viewData->_geometry->setVertexArray(viewData->_vertices.get());
283
284        osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array(1);
285        (*colors)[0].set(1.0f,1.0f,1.0f,1.0f);
286        viewData->_geometry->setColorArray(colors.get(), osg::Array::BIND_OVERALL);
287
288        osg::ref_ptr<osg::Vec2Array> texcoords = new osg::Vec2Array(4);
289        (*texcoords)[0].set(0.0f,1.0f);
290        (*texcoords)[1].set(0.0f,0.0f);
291        (*texcoords)[2].set(1.0f,1.0f);
292        (*texcoords)[3].set(1.0f,0.0f);
293        viewData->_geometry->setTexCoordArray(0, texcoords.get(), osg::Array::BIND_PER_VERTEX);
294
295        viewData->_geometry->addPrimitiveSet(new osg::DrawArrays(GL_TRIANGLE_STRIP,0,4));
296
297
298        osg::ref_ptr<osg::StateSet> stateset = viewData->_geometry->getOrCreateStateSet();
299
300        stateset->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);
301        stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
302        stateset->setMode(GL_BLEND, osg::StateAttribute::OFF);
303        stateset->setMode(GL_ALPHA_TEST, osg::StateAttribute::OFF);
304        stateset->setAttribute(new osg::Depth(osg::Depth::LEQUAL));
305        stateset->setRenderBinDetails(10,"DepthSortedBin");
306
307        osg::ref_ptr<osg::Program> program = new osg::Program;
308        stateset->setAttribute(program.get());
309
310        // get vertex shaders from source
311        osg::ref_ptr<osg::Shader> vertexShader = osgDB::readRefShaderFile(osg::Shader::VERTEX, "shaders/volume_color_depth.vert");
312        if (vertexShader.valid())
313        {
314            program->addShader(vertexShader.get());
315        }
316#if 0
317        else
318        {
319            #include "Shaders/volume_color_depth_vert.cpp"
320            program->addShader(new osg::Shader(osg::Shader::VERTEX, volume_color_depth_vert));
321        }
322#endif
323        // get fragment shaders from source
324        osg::ref_ptr<osg::Shader> fragmentShader = osgDB::readRefShaderFile(osg::Shader::FRAGMENT, "shaders/volume_color_depth.frag");
325        if (fragmentShader.valid())
326        {
327            program->addShader(fragmentShader.get());
328        }
329#if 0
330        else
331        {
332            #include "Shaders/volume_color_depth_frag.cpp"
333            program->addShader(new osg::Shader(osg::Shader::FRAGMENT, volume_color_depth_frag));
334        }
335#endif
336        viewData->_stateset = new osg::StateSet;
337        viewData->_stateset->addUniform(new osg::Uniform("colorTexture",0));
338        viewData->_stateset->addUniform(new osg::Uniform("depthTexture",1));
339
340        viewData->_stateset->setTextureAttributeAndModes(0, viewData->_colorTexture.get(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE);
341        viewData->_stateset->setTextureAttributeAndModes(1, viewData->_depthTexture.get(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE);
342
343        viewData->_viewportDimensionsUniform = new osg::Uniform("viewportDimensions",osg::Vec4(0.0,0.0,1280.0,1024.0));
344        viewData->_stateset->addUniform(viewData->_viewportDimensionsUniform.get());
345
346        geode->setStateSet(viewData->_stateset.get());
347
348    }
349    else
350    {
351        // OSG_NOTICE<<"Reusing ViewData"<<std::endl;
352
353    }
354
355    osg::Matrix projectionMatrix = *(cv->getProjectionMatrix());
356    osg::Matrix modelviewMatrix = *(cv->getModelViewMatrix());
357
358
359    // new frame so need to clear last frames log of VolumeTiles
360    viewData->clearTiles();
361
362    osg::Viewport* viewport = cv->getCurrentRenderStage()->getViewport();
363    if (viewport)
364    {
365        viewData->_viewportDimensionsUniform->set(osg::Vec4(viewport->x(), viewport->y(), viewport->width(),viewport->height()));
366
367        int textureWidth = static_cast<int>(viewport->width());
368        int textureHeight = static_cast<int>(viewport->height());
369
370        if (textureWidth != viewData->_colorTexture->getTextureWidth() ||
371            textureHeight != viewData->_colorTexture->getTextureHeight())
372        {
373            OSG_NOTICE<<"Need to change texture size to "<<textureWidth<<", "<< textureHeight<<std::endl;
374            viewData->_colorTexture->setTextureSize(textureWidth, textureHeight);
375            viewData->_colorTexture->dirtyTextureObject();
376            viewData->_depthTexture->setTextureSize(textureWidth, textureHeight);
377            viewData->_depthTexture->dirtyTextureObject();
378            viewData->_rttCamera->setViewport(0, 0, textureWidth, textureHeight);
379            if (viewData->_rttCamera->getRenderingCache())
380            {
381                viewData->_rttCamera->getRenderingCache()->releaseGLObjects(0);
382            }
383        }
384    }
385
386    cv->setUserValue("VolumeSceneTraversal",std::string("RenderToTexture"));
387
388    //OSG_NOTICE<<"Ready to traverse RTT Camera"<<std::endl;
389    //OSG_NOTICE<<"   RTT Camera ProjectionMatrix Before "<<viewData->_rttCamera->getProjectionMatrix()<<std::endl;
390    viewData->_rttCamera->accept(nv);
391
392    //OSG_NOTICE<<"   RTT Camera ProjectionMatrix After "<<viewData->_rttCamera->getProjectionMatrix()<<std::endl;
393    //OSG_NOTICE<<"   cv ProjectionMatrix After "<<*(cv->getProjectionMatrix())<<std::endl;
394
395    //OSG_NOTICE<<"  after RTT near ="<<cv->getCalculatedNearPlane()<<std::endl;
396    //OSG_NOTICE<<"  after RTT far ="<<cv->getCalculatedFarPlane()<<std::endl;
397
398    //OSG_NOTICE<<"tileVisited()"<<viewData->_tiles.size()<<std::endl;
399
400
401    typedef osgUtil::CullVisitor::value_type NearFarValueType;
402    NearFarValueType calculatedNearPlane = std::numeric_limits<NearFarValueType>::max();
403    NearFarValueType calculatedFarPlane = -std::numeric_limits<NearFarValueType>::max();
404    if (viewData->_rttCamera->getUserValue("CalculatedNearPlane",calculatedNearPlane) &&
405        viewData->_rttCamera->getUserValue("CalculatedFarPlane",calculatedFarPlane))
406    {
407        calculatedNearPlane *= 0.5;
408        calculatedFarPlane *= 2.0;
409
410        //OSG_NOTICE<<"Got from RTTCamera CalculatedNearPlane="<<calculatedNearPlane<<std::endl;
411        //OSG_NOTICE<<"Got from RTTCamera CalculatedFarPlane="<<calculatedFarPlane<<std::endl;
412        if (calculatedNearPlane < cv->getCalculatedNearPlane()) cv->setCalculatedNearPlane(calculatedNearPlane);
413        if (calculatedFarPlane > cv->getCalculatedFarPlane()) cv->setCalculatedFarPlane(calculatedFarPlane);
414    }
415
416    if (calculatedFarPlane>calculatedNearPlane)
417    {
418        cv->clampProjectionMatrix(projectionMatrix, calculatedNearPlane, calculatedFarPlane);
419    }
420
421    osg::Matrix inv_projectionModelViewMatrix;
422    inv_projectionModelViewMatrix.invert(modelviewMatrix*projectionMatrix);
423
424    double depth = 1.0;
425    osg::Vec3d v00 = osg::Vec3d(-1.0,-1.0,depth)*inv_projectionModelViewMatrix;
426    osg::Vec3d v01 = osg::Vec3d(-1.0,1.0,depth)*inv_projectionModelViewMatrix;
427    osg::Vec3d v10 = osg::Vec3d(1.0,-1.0,depth)*inv_projectionModelViewMatrix;
428    osg::Vec3d v11 = osg::Vec3d(1.0,1.0,depth)*inv_projectionModelViewMatrix;
429
430    // OSG_NOTICE<<"v00= "<<v00<<std::endl;
431    // OSG_NOTICE<<"v01= "<<v01<<std::endl;
432    // OSG_NOTICE<<"v10= "<<v10<<std::endl;
433    // OSG_NOTICE<<"v11= "<<v11<<std::endl;
434
435    (*(viewData->_vertices))[0] = v01;
436    (*(viewData->_vertices))[1] = v00;
437    (*(viewData->_vertices))[2] = v11;
438    (*(viewData->_vertices))[3] = v10;
439    viewData->_geometry->dirtyBound();
440
441    //OSG_NOTICE<<"  new after RTT near ="<<cv->getCalculatedNearPlane()<<std::endl;
442    //OSG_NOTICE<<"  new after RTT far ="<<cv->getCalculatedFarPlane()<<std::endl;
443
444    viewData->_backdropSubgraph->accept(*cv);
445
446    osg::NodePath nodePathPriorToTraversingSubgraph = cv->getNodePath();
447    cv->setUserValue("VolumeSceneTraversal",std::string("Post"));
448
449    // for each tile that needs post rendering we need to add it into current RenderStage.
450    Tiles& tiles = viewData->_tiles;
451    for(Tiles::iterator itr = tiles.begin();
452        itr != tiles.end();
453        ++itr)
454    {
455        TileData* tileData = itr->second.get();
456        if (!tileData || !(tileData->active))
457        {
458            OSG_INFO<<"Skipping TileData that is inactive : "<<tileData<<std::endl;
459            continue;
460        }
461
462        unsigned int numStateSetPushed = 0;
463
464        // OSG_NOTICE<<"VolumeTile to add "<<tileData->projectionMatrix.get()<<", "<<tileData->modelviewMatrix.get()<<std::endl;
465
466
467        osg::NodePath& nodePath = tileData->nodePath;
468
469        cv->getNodePath() = nodePath;
470        cv->pushProjectionMatrix(tileData->projectionMatrix.get());
471        cv->pushModelViewMatrix(tileData->modelviewMatrix.get(), osg::Transform::ABSOLUTE_RF_INHERIT_VIEWPOINT);
472
473
474        cv->pushStateSet(viewData->_stateset.get());
475        ++numStateSetPushed;
476
477        cv->pushStateSet(tileData->stateset.get());
478        ++numStateSetPushed;
479
480        osg::NodePath::iterator np_itr = nodePath.begin();
481
482        // skip over all nodes above VolumeScene as this will have already been traverse by CullVisitor
483        while(np_itr!=nodePath.end() && (*np_itr)!=viewData->_rttCamera.get()) { ++np_itr; }
484        if (np_itr!=nodePath.end()) ++np_itr;
485
486        // push the stateset on the nodes between this VolumeScene and the VolumeTile
487        for(osg::NodePath::iterator ss_itr = np_itr;
488            ss_itr != nodePath.end();
489            ++ss_itr)
490        {
491            if ((*ss_itr)->getStateSet())
492            {
493                numStateSetPushed++;
494                cv->pushStateSet((*ss_itr)->getStateSet());
495                // OSG_NOTICE<<"  pushing StateSet"<<std::endl;
496            }
497        }
498        cv->traverse(*(tileData->nodePath.back()));
499
500        // pop the StateSet's
501        for(unsigned int i=0; i<numStateSetPushed; ++i)
502        {
503            cv->popStateSet();
504            // OSG_NOTICE<<"  popping StateSet"<<std::endl;
505        }
506
507        cv->popModelViewMatrix();
508        cv->popProjectionMatrix();
509    }
510
511    // need to synchronize projection matrices:
512    //    current CV projection matrix
513    //    main scene RTT Camera projection matrix
514    //    each tile RTT Camera
515    //    each tile final render.
516
517    cv->getNodePath() = nodePathPriorToTraversingSubgraph;
518}
Note: See TracBrowser for help on using the browser.