root/OpenSceneGraph/trunk/src/osgVolume/MultipassTechnique.cpp @ 13948

Revision 13948, 17.0 kB (checked in by robert, 36 hours 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/MultipassTechnique>
15#include <osgVolume/VolumeTile>
16#include <osgVolume/VolumeScene>
17
18#include <osg/Geometry>
19#include <osg/ValueObject>
20#include <osg/io_utils>
21
22#include <osg/Program>
23#include <osg/Material>
24#include <osg/CullFace>
25#include <osg/TexGen>
26#include <osg/Texture1D>
27#include <osg/Texture2D>
28#include <osg/Texture3D>
29#include <osg/TransferFunction>
30
31#include <osgDB/ReadFile>
32#include <osgDB/WriteFile>
33
34namespace osgVolume
35{
36
37
38MultipassTechnique::MultipassTechnique()
39{
40}
41
42MultipassTechnique::MultipassTechnique(const MultipassTechnique& fft,const osg::CopyOp& copyop):
43    VolumeTechnique(fft,copyop)
44{
45}
46
47MultipassTechnique::~MultipassTechnique()
48{
49}
50
51void MultipassTechnique::init()
52{
53    OSG_INFO<<"MultipassTechnique::init()"<<std::endl;
54
55    if (!_volumeTile)
56    {
57        OSG_NOTICE<<"MultipassTechnique::init(), error no volume tile assigned."<<std::endl;
58        return;
59    }
60
61    if (_volumeTile->getLayer()==0)
62    {
63        OSG_NOTICE<<"MultipassTechnique::init(), error no layer assigend to volume tile."<<std::endl;
64        return;
65    }
66
67    if (_volumeTile->getLayer()->getImage()==0)
68    {
69        OSG_NOTICE<<"MultipassTechnique::init(), error no image assigned to layer."<<std::endl;
70        return;
71    }
72
73    OSG_NOTICE<<"MultipassTechnique::init() Need to set up"<<std::endl;
74
75    CollectPropertiesVisitor cpv;
76    if (_volumeTile->getLayer()->getProperty())
77    {
78        _volumeTile->getLayer()->getProperty()->accept(cpv);
79    }
80
81    osg::ref_ptr<osg::Geode> geode = new osg::Geode;
82
83    {
84        osg::Geometry* geom = new osg::Geometry;
85
86        osg::Vec3Array* coords = new osg::Vec3Array(8);
87        (*coords)[0] = osg::Vec3d(0.0,0.0,0.0);
88        (*coords)[1] = osg::Vec3d(1.0,0.0,0.0);
89        (*coords)[2] = osg::Vec3d(1.0,1.0,0.0);
90        (*coords)[3] = osg::Vec3d(0.0,1.0,0.0);
91        (*coords)[4] = osg::Vec3d(0.0,0.0,1.0);
92        (*coords)[5] = osg::Vec3d(1.0,0.0,1.0);
93        (*coords)[6] = osg::Vec3d(1.0,1.0,1.0);
94        (*coords)[7] = osg::Vec3d(0.0,1.0,1.0);
95        geom->setVertexArray(coords);
96
97        osg::Vec4Array* colours = new osg::Vec4Array(1);
98        (*colours)[0].set(1.0f,1.0f,1.0,1.0f);
99        geom->setColorArray(colours, osg::Array::BIND_OVERALL);
100
101        osg::DrawElementsUShort* drawElements = new osg::DrawElementsUShort(GL_QUADS);
102        // bottom
103        drawElements->push_back(3);
104        drawElements->push_back(2);
105        drawElements->push_back(1);
106        drawElements->push_back(0);
107
108        // bottom
109        drawElements->push_back(7);//7623
110        drawElements->push_back(6);
111        drawElements->push_back(2);
112        drawElements->push_back(3);
113
114        // left
115        drawElements->push_back(4);//4730
116        drawElements->push_back(7);
117        drawElements->push_back(3);
118        drawElements->push_back(0);
119
120        // right
121        drawElements->push_back(1);//1265
122        drawElements->push_back(2);
123        drawElements->push_back(6);
124        drawElements->push_back(5);
125
126        // front
127        drawElements->push_back(5);//5401
128        drawElements->push_back(4);
129        drawElements->push_back(0);
130        drawElements->push_back(1);
131
132        // top
133        drawElements->push_back(4);//4567
134        drawElements->push_back(5);
135        drawElements->push_back(6);
136        drawElements->push_back(7);
137
138        geom->addPrimitiveSet(drawElements);
139
140        geode->addDrawable(geom);
141
142    }
143
144    _transform = new osg::MatrixTransform;
145
146    // handle locators
147    Locator* masterLocator = _volumeTile->getLocator();
148    Locator* layerLocator = _volumeTile->getLayer()->getLocator();
149
150    osg::TransferFunction1D* tf = 0;
151
152    if (!masterLocator && layerLocator) masterLocator = layerLocator;
153    if (!layerLocator && masterLocator) layerLocator = masterLocator;
154
155    osg::Matrix geometryMatrix;
156    if (masterLocator)
157    {
158        geometryMatrix = masterLocator->getTransform();
159        _transform->setMatrix(geometryMatrix);
160        masterLocator->addCallback(new TransformLocatorCallback(_transform.get()));
161    }
162
163    osg::Matrix imageMatrix;
164    if (layerLocator)
165    {
166        imageMatrix = layerLocator->getTransform();
167    }
168
169    OSG_NOTICE<<"MultipassTechnique::init() : geometryMatrix = "<<geometryMatrix<<std::endl;
170    OSG_NOTICE<<"MultipassTechnique::init() : imageMatrix = "<<imageMatrix<<std::endl;
171
172    osg::ref_ptr<osg::StateSet> stateset = _transform->getOrCreateStateSet();
173
174    unsigned int texgenTextureUnit = 0;
175    unsigned int volumeTextureUnit = 2;
176
177    // set up uniforms
178    {
179        stateset->addUniform(new osg::Uniform("colorTexture",0));
180        stateset->addUniform(new osg::Uniform("depthTexture",1));
181
182        stateset->setMode(GL_ALPHA_TEST,osg::StateAttribute::ON);
183
184        float alphaFuncValue = 0.1;
185        if (cpv._isoProperty.valid())
186        {
187            alphaFuncValue = cpv._isoProperty->getValue();
188        }
189
190        if (cpv._sampleRatioProperty.valid())
191            stateset->addUniform(cpv._sampleRatioProperty->getUniform());
192        else
193            stateset->addUniform(new osg::Uniform("SampleRatioValue",1.0f));
194
195
196        if (cpv._transparencyProperty.valid())
197            stateset->addUniform(cpv._transparencyProperty->getUniform());
198        else
199            stateset->addUniform(new osg::Uniform("TransparencyValue",1.0f));
200
201
202        if (cpv._afProperty.valid())
203            stateset->addUniform(cpv._afProperty->getUniform());
204        else
205            stateset->addUniform(new osg::Uniform("AlphaFuncValue",alphaFuncValue));
206
207
208        if (cpv._isoProperty.valid())
209            stateset->addUniform(cpv._isoProperty->getUniform());
210        else
211            stateset->addUniform(new osg::Uniform("IsoSurfaceValue",alphaFuncValue));
212
213        if (cpv._tfProperty.valid())
214        {
215            tf = dynamic_cast<osg::TransferFunction1D*>(cpv._tfProperty->getTransferFunction());
216        }
217
218#if 1
219        osg::ref_ptr<osg::TexGen> texgen = new osg::TexGen;
220        texgen->setMode(osg::TexGen::OBJECT_LINEAR);
221        texgen->setPlanesFromMatrix( geometryMatrix * osg::Matrix::inverse(imageMatrix));
222
223        if (masterLocator)
224        {
225            osg::ref_ptr<TexGenLocatorCallback> locatorCallback = new TexGenLocatorCallback(texgen, masterLocator, layerLocator);
226            masterLocator->addCallback(locatorCallback.get());
227            if (masterLocator != layerLocator)
228            {
229                if (layerLocator) layerLocator->addCallback(locatorCallback.get());
230            }
231        }
232
233        stateset->setTextureAttributeAndModes(texgenTextureUnit, texgen.get(), osg::StateAttribute::ON);
234#endif
235    }
236
237
238    // set up 3D texture
239    osg::ref_ptr<osg::Image> image_3d = _volumeTile->getLayer()->getImage();
240    osg::ref_ptr<osg::Texture3D> texture3D = new osg::Texture3D;
241    {
242        osg::Texture::InternalFormatMode internalFormatMode = osg::Texture::USE_IMAGE_DATA_FORMAT;
243#if 1
244        osg::Texture::FilterMode minFilter = osg::Texture::LINEAR;
245        osg::Texture::FilterMode magFilter = osg::Texture::LINEAR;
246#else
247        osg::Texture::FilterMode minFilter = osg::Texture::NEAREST;
248        osg::Texture::FilterMode magFilter = osg::Texture::NEAREST;
249#endif
250
251        // set up the 3d texture itself,
252        // note, well set the filtering up so that mip mapping is disabled,
253        // gluBuild3DMipsmaps doesn't do a very good job of handled the
254        // imbalanced dimensions of the 256x256x4 texture.
255        texture3D->setResizeNonPowerOfTwoHint(false);
256        texture3D->setFilter(osg::Texture3D::MIN_FILTER,minFilter);
257        texture3D->setFilter(osg::Texture3D::MAG_FILTER, magFilter);
258        texture3D->setWrap(osg::Texture3D::WRAP_R,osg::Texture3D::CLAMP_TO_BORDER);
259        texture3D->setWrap(osg::Texture3D::WRAP_S,osg::Texture3D::CLAMP_TO_BORDER);
260        texture3D->setWrap(osg::Texture3D::WRAP_T,osg::Texture3D::CLAMP_TO_BORDER);
261        texture3D->setBorderColor(osg::Vec4(0.0,0.0,0.0,0.0));
262        if (image_3d->getPixelFormat()==GL_ALPHA ||
263            image_3d->getPixelFormat()==GL_LUMINANCE)
264        {
265            texture3D->setInternalFormatMode(osg::Texture3D::USE_USER_DEFINED_FORMAT);
266            texture3D->setInternalFormat(GL_INTENSITY);
267        }
268        else
269        {
270            texture3D->setInternalFormatMode(internalFormatMode);
271        }
272        texture3D->setImage(image_3d);
273
274        stateset->setTextureAttributeAndModes(volumeTextureUnit, texture3D, osg::StateAttribute::ON);
275
276        osg::ref_ptr<osg::Uniform> baseTextureSampler = new osg::Uniform("volumeTexture", int(volumeTextureUnit));
277        stateset->addUniform(baseTextureSampler.get());
278
279        osg::ref_ptr<osg::Uniform> volumeCellSize = new osg::Uniform("volumeCellSize", osg::Vec3(1.0f/static_cast<float>(image_3d->s()),1.0f/static_cast<float>(image_3d->t()),1.0f/static_cast<float>(image_3d->r())));
280        stateset->addUniform(volumeCellSize.get());
281
282        OSG_NOTICE<<"Texture Dimensions "<<image_3d->s()<<", "<<image_3d->t()<<", "<<image_3d->r()<<std::endl;
283    }
284
285    if (tf)
286    {
287        OSG_NOTICE<<"Setting up TransferFunction"<<std::endl;
288
289        float tfScale = 1.0f;
290        float tfOffset = 0.0f;
291
292        ImageLayer* imageLayer = dynamic_cast<ImageLayer*>(_volumeTile->getLayer());
293        if (imageLayer)
294        {
295            tfOffset = (imageLayer->getTexelOffset()[3] - tf->getMinimum()) / (tf->getMaximum() - tf->getMinimum());
296            tfScale = imageLayer->getTexelScale()[3] / (tf->getMaximum() - tf->getMinimum());
297        }
298        else
299        {
300            tfOffset = -tf->getMinimum() / (tf->getMaximum()-tf->getMinimum());
301            tfScale = 1.0f / (tf->getMaximum()-tf->getMinimum());
302        }
303        osg::ref_ptr<osg::Texture1D> tf_texture = new osg::Texture1D;
304        tf_texture->setImage(tf->getImage());
305
306        tf_texture->setResizeNonPowerOfTwoHint(false);
307        tf_texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
308        tf_texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
309        tf_texture->setWrap(osg::Texture::WRAP_R,osg::Texture::CLAMP_TO_EDGE);
310
311        unsigned int transferFunctionTextureUnit = volumeTextureUnit+1;
312
313        stateset->setTextureAttributeAndModes(transferFunctionTextureUnit, tf_texture.get(), osg::StateAttribute::ON);
314        stateset->addUniform(new osg::Uniform("tfTexture",int(transferFunctionTextureUnit)));
315        stateset->addUniform(new osg::Uniform("tfOffset",tfOffset));
316        stateset->addUniform(new osg::Uniform("tfScale",tfScale));
317
318    }
319
320
321    osg::ref_ptr<osg::Shader> computeRayColorShader = osgDB::readRefShaderFile(osg::Shader::FRAGMENT, "shaders/volume_compute_ray_color.frag");
322#if 0
323    if (!computeRayColorShader)
324    {
325        #include "Shaders/volume_compute_ray_color_frag.cpp";
326        computeRayColorShader = new osg::Shader(osg::Shader::FRAGMENT, volume_compute_ray_color_frag);
327    }
328#endif
329
330    // set up the renderin of the front faces
331    {
332        osg::ref_ptr<osg::Group> front_face_group = new osg::Group;
333        front_face_group->addChild(geode.get());
334        _transform->addChild(front_face_group.get());
335
336        osg::ref_ptr<osg::StateSet> front_face_stateset = front_face_group->getOrCreateStateSet();
337        front_face_stateset->setAttributeAndModes(new osg::CullFace(osg::CullFace::BACK), osg::StateAttribute::ON);
338
339        osg::ref_ptr<osg::Program> program = new osg::Program;
340        front_face_stateset->setAttribute(program);
341
342        // get vertex shaders from source
343        osg::ref_ptr<osg::Shader> vertexShader = osgDB::readRefShaderFile(osg::Shader::VERTEX, "shaders/volume_multipass_front.vert");
344        if (vertexShader.valid())
345        {
346            program->addShader(vertexShader.get());
347        }
348#if 0
349        else
350        {
351            #include "Shaders/volume_color_depth_vert.cpp"
352            program->addShader(new osg::Shader(osg::Shader::VERTEX, volume_color_depth_vert));
353        }
354#endif
355        // get fragment shaders from source
356        osg::ref_ptr<osg::Shader> fragmentShader = osgDB::readRefShaderFile(osg::Shader::FRAGMENT, "shaders/volume_multipass_front.frag");
357        if (fragmentShader.valid())
358        {
359            program->addShader(fragmentShader.get());
360        }
361#if 0
362        else
363        {
364            #include "Shaders/volume_color_depth_frag.cpp"
365            program->addShader(new osg::Shader(osg::Shader::FRAGMENT, volume_color_depth_frag));
366        }
367#endif
368
369        if (computeRayColorShader.valid())
370        {
371            program->addShader(computeRayColorShader.get());
372        }
373    }
374
375
376    // set up the rendering of the back faces
377    {
378        osg::ref_ptr<osg::Group> back_face_group = new osg::Group;
379        back_face_group->addChild(geode.get());
380        _transform->addChild(back_face_group.get());
381
382        osg::ref_ptr<osg::StateSet> back_face_stateset = back_face_group->getOrCreateStateSet();
383        back_face_stateset->setAttributeAndModes(new osg::CullFace(osg::CullFace::FRONT), osg::StateAttribute::ON);
384
385        osg::ref_ptr<osg::Program> program = new osg::Program;
386        back_face_stateset->setAttribute(program);
387
388        // get vertex shaders from source
389        osg::ref_ptr<osg::Shader> vertexShader = osgDB::readRefShaderFile(osg::Shader::VERTEX, "shaders/volume_multipass_back.vert");
390        if (vertexShader.valid())
391        {
392            program->addShader(vertexShader.get());
393        }
394#if 0
395        else
396        {
397            #include "Shaders/volume_color_depth_vert.cpp"
398            program->addShader(new osg::Shader(osg::Shader::VERTEX, volume_color_depth_vert));
399        }
400#endif
401        // get fragment shaders from source
402        osg::ref_ptr<osg::Shader> fragmentShader = osgDB::readRefShaderFile(osg::Shader::FRAGMENT, "shaders/volume_multipass_back.frag");
403        if (fragmentShader.valid())
404        {
405            program->addShader(fragmentShader.get());
406        }
407#if 0
408        else
409        {
410            #include "Shaders/volume_color_depth_frag.cpp"
411            program->addShader(new osg::Shader(osg::Shader::FRAGMENT, volume_color_depth_frag));
412        }
413#endif
414        if (computeRayColorShader.valid())
415        {
416            program->addShader(computeRayColorShader.get());
417        }
418
419    }
420
421
422    if (cpv._sampleRatioWhenMovingProperty.valid())
423    {
424        _whenMovingStateSet = new osg::StateSet;
425        _whenMovingStateSet->addUniform(cpv._sampleRatioWhenMovingProperty->getUniform(), osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);
426    }
427
428}
429
430void MultipassTechnique::update(osgUtil::UpdateVisitor* /*uv*/)
431{
432//    OSG_NOTICE<<"MultipassTechnique:update(osgUtil::UpdateVisitor* nv):"<<std::endl;
433}
434
435void MultipassTechnique::cull(osgUtil::CullVisitor* cv)
436{
437    std::string traversalPass;
438    bool postTraversal = cv->getUserValue("VolumeSceneTraversal", traversalPass) && traversalPass=="Post";
439
440    // OSG_NOTICE<<"MultipassTechnique::cull()  traversalPass="<<traversalPass<<std::endl;
441
442    if (postTraversal)
443    {
444        if (_whenMovingStateSet.valid() && isMoving(cv))
445        {
446            OSG_NOTICE<<"Using MovingStateSet"<<std::endl;
447            cv->pushStateSet(_whenMovingStateSet.get());
448            _transform->accept(*cv);
449            cv->popStateSet();
450        }
451        else
452        {
453            OSG_NOTICE<<"NOT using MovingStateSet"<<std::endl;
454            _transform->accept(*cv);
455        }
456    }
457    else
458    {
459        osg::NodePath& nodePath = cv->getNodePath();
460        for(osg::NodePath::reverse_iterator itr = nodePath.rbegin();
461            itr != nodePath.rend();
462            ++itr)
463        {
464            osgVolume::VolumeScene* vs = dynamic_cast<osgVolume::VolumeScene*>(*itr);
465            if (vs)
466            {
467                vs->tileVisited(cv, getVolumeTile());
468                break;
469            }
470        }
471    }
472}
473
474void MultipassTechnique::cleanSceneGraph()
475{
476    OSG_NOTICE<<"MultipassTechnique::cleanSceneGraph()"<<std::endl;
477}
478
479void MultipassTechnique::traverse(osg::NodeVisitor& nv)
480{
481    // OSG_NOTICE<<"MultipassTechnique::traverse(osg::NodeVisitor& nv)"<<std::endl;
482    if (!_volumeTile) return;
483
484    // if app traversal update the frame count.
485    if (nv.getVisitorType()==osg::NodeVisitor::UPDATE_VISITOR)
486    {
487        if (_volumeTile->getDirty()) _volumeTile->init();
488
489        osgUtil::UpdateVisitor* uv = dynamic_cast<osgUtil::UpdateVisitor*>(&nv);
490        if (uv)
491        {
492            update(uv);
493            return;
494        }
495
496    }
497    else if (nv.getVisitorType()==osg::NodeVisitor::CULL_VISITOR)
498    {
499        osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(&nv);
500        if (cv)
501        {
502            cull(cv);
503            return;
504        }
505    }
506
507
508    if (_volumeTile->getDirty())
509    {
510        OSG_INFO<<"******* Doing init ***********"<<std::endl;
511        _volumeTile->init();
512    }
513}
514
515
516} // end of osgVolume namespace
Note: See TracBrowser for help on using the browser.