root/OpenSceneGraph/trunk/src/osgVolume/RayTracedTechnique.cpp @ 13041

Revision 13041, 19.2 kB (checked in by robert, 3 years ago)

Ran script to remove trailing spaces and tabs

  • Property svn:eol-style set to native
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/RayTracedTechnique>
15#include <osgVolume/VolumeTile>
16
17#include <osg/Geometry>
18#include <osg/io_utils>
19
20#include <osg/Program>
21#include <osg/TexGen>
22#include <osg/Texture1D>
23#include <osg/Texture2D>
24#include <osg/Texture3D>
25#include <osg/TransferFunction>
26
27#include <osgDB/ReadFile>
28#include <osgDB/WriteFile>
29
30namespace osgVolume
31{
32
33class TransformLocatorCallback : public Locator::LocatorCallback
34{
35    public:
36
37        TransformLocatorCallback(osg::MatrixTransform* transform): _transform(transform) {}
38
39        void locatorModified(Locator* locator)
40        {
41            if (_transform.valid()) _transform->setMatrix(locator->getTransform());
42        }
43
44    protected:
45
46        osg::observer_ptr<osg::MatrixTransform> _transform;
47};
48
49
50class TexGenLocatorCallback : public Locator::LocatorCallback
51{
52    public:
53
54        TexGenLocatorCallback(osg::TexGen* texgen, Locator* geometryLocator, Locator* imageLocator):
55            _texgen(texgen),
56            _geometryLocator(geometryLocator),
57            _imageLocator(imageLocator) {}
58
59        void locatorModified(Locator*)
60        {
61            if (!_texgen || !_geometryLocator || !_imageLocator) return;
62
63            _texgen->setPlanesFromMatrix(
64                _geometryLocator->getTransform() *
65                osg::Matrix::inverse(_imageLocator->getTransform()));
66        }
67
68    protected:
69
70        osg::observer_ptr<osg::TexGen> _texgen;
71        osg::observer_ptr<osgVolume::Locator> _geometryLocator;
72        osg::observer_ptr<osgVolume::Locator> _imageLocator;
73};
74
75
76RayTracedTechnique::RayTracedTechnique()
77{
78}
79
80RayTracedTechnique::RayTracedTechnique(const RayTracedTechnique& fft,const osg::CopyOp& copyop):
81    VolumeTechnique(fft,copyop)
82{
83}
84
85RayTracedTechnique::~RayTracedTechnique()
86{
87}
88
89enum ShadingModel
90{
91    Standard,
92    Light,
93    Isosurface,
94    MaximumIntensityProjection
95};
96
97void RayTracedTechnique::init()
98{
99    OSG_INFO<<"RayTracedTechnique::init()"<<std::endl;
100
101    if (!_volumeTile)
102    {
103        OSG_NOTICE<<"RayTracedTechnique::init(), error no volume tile assigned."<<std::endl;
104        return;
105    }
106
107    if (_volumeTile->getLayer()==0)
108    {
109        OSG_NOTICE<<"RayTracedTechnique::init(), error no layer assigend to volume tile."<<std::endl;
110        return;
111    }
112
113    if (_volumeTile->getLayer()->getImage()==0)
114    {
115        OSG_NOTICE<<"RayTracedTechnique::init(), error no image assigned to layer."<<std::endl;
116        return;
117    }
118
119     ShadingModel shadingModel = Isosurface;
120     float alphaFuncValue = 0.1;
121
122    _transform = new osg::MatrixTransform;
123
124    osg::ref_ptr<osg::Geode> geode = new osg::Geode;
125
126    _transform->addChild(geode.get());
127
128    osg::Image* image_3d = 0;
129    osg::TransferFunction1D* tf = 0;
130    Locator* masterLocator = _volumeTile->getLocator();
131    Locator* layerLocator = _volumeTile->getLayer()->getLocator();
132
133    image_3d = _volumeTile->getLayer()->getImage();
134
135
136    CollectPropertiesVisitor cpv;
137    if (_volumeTile->getLayer()->getProperty())
138    {
139        _volumeTile->getLayer()->getProperty()->accept(cpv);
140    }
141
142    if (cpv._isoProperty.valid())
143    {
144        shadingModel = Isosurface;
145        alphaFuncValue = cpv._isoProperty->getValue();
146    }
147    else if (cpv._mipProperty.valid())
148    {
149        shadingModel = MaximumIntensityProjection;
150    }
151    else if (cpv._lightingProperty.valid())
152    {
153        shadingModel = Light;
154    }
155    else
156    {
157        shadingModel = Standard;
158    }
159
160    if (cpv._tfProperty.valid())
161    {
162        tf = dynamic_cast<osg::TransferFunction1D*>(cpv._tfProperty->getTransferFunction());
163    }
164
165    if (cpv._afProperty.valid())
166    {
167        alphaFuncValue = cpv._afProperty->getValue();
168    }
169
170
171    if (!masterLocator && layerLocator) masterLocator = layerLocator;
172    if (!layerLocator && masterLocator) layerLocator = masterLocator;
173
174
175    osg::Matrix geometryMatrix;
176    if (masterLocator)
177    {
178        geometryMatrix = masterLocator->getTransform();
179        _transform->setMatrix(geometryMatrix);
180        masterLocator->addCallback(new TransformLocatorCallback(_transform.get()));
181    }
182
183    osg::Matrix imageMatrix;
184    if (layerLocator)
185    {
186        imageMatrix = layerLocator->getTransform();
187    }
188
189    OSG_INFO<<"RayTracedTechnique::init() : geometryMatrix = "<<geometryMatrix<<std::endl;
190    OSG_INFO<<"RayTracedTechnique::init() : imageMatrix = "<<imageMatrix<<std::endl;
191
192    osg::Texture::InternalFormatMode internalFormatMode = osg::Texture::USE_IMAGE_DATA_FORMAT;
193
194    {
195
196        osg::Texture::FilterMode minFilter = osg::Texture::LINEAR;
197        osg::Texture::FilterMode magFilter = osg::Texture::LINEAR;
198
199        osg::StateSet* stateset = geode->getOrCreateStateSet();
200
201        stateset->setMode(GL_ALPHA_TEST,osg::StateAttribute::ON);
202
203        osg::Program* program = new osg::Program;
204        stateset->setAttribute(program);
205
206        // get shaders from source
207
208        osg::Shader* vertexShader = osgDB::readShaderFile(osg::Shader::VERTEX, "shaders/volume.vert");
209        if (vertexShader)
210        {
211            program->addShader(vertexShader);
212        }
213        else
214        {
215            #include "Shaders/volume_vert.cpp"
216            program->addShader(new osg::Shader(osg::Shader::VERTEX, volume_vert));
217        }
218
219        {
220            // set up the 3d texture itself,
221            // note, well set the filtering up so that mip mapping is disabled,
222            // gluBuild3DMipsmaps doesn't do a very good job of handled the
223            // imbalanced dimensions of the 256x256x4 texture.
224            osg::Texture3D* texture3D = new osg::Texture3D;
225            texture3D->setResizeNonPowerOfTwoHint(false);
226            texture3D->setFilter(osg::Texture3D::MIN_FILTER,minFilter);
227            texture3D->setFilter(osg::Texture3D::MAG_FILTER, magFilter);
228            texture3D->setWrap(osg::Texture3D::WRAP_R,osg::Texture3D::CLAMP_TO_BORDER);
229            texture3D->setWrap(osg::Texture3D::WRAP_S,osg::Texture3D::CLAMP_TO_BORDER);
230            texture3D->setWrap(osg::Texture3D::WRAP_T,osg::Texture3D::CLAMP_TO_BORDER);
231            texture3D->setBorderColor(osg::Vec4(0.0,0.0,0.0,0.0));
232            if (image_3d->getPixelFormat()==GL_ALPHA ||
233                image_3d->getPixelFormat()==GL_LUMINANCE)
234            {
235                texture3D->setInternalFormatMode(osg::Texture3D::USE_USER_DEFINED_FORMAT);
236                texture3D->setInternalFormat(GL_INTENSITY);
237            }
238            else
239            {
240                texture3D->setInternalFormatMode(internalFormatMode);
241            }
242            texture3D->setImage(image_3d);
243
244            stateset->setTextureAttributeAndModes(0,texture3D,osg::StateAttribute::ON);
245
246            osg::Uniform* baseTextureSampler = new osg::Uniform("baseTexture",0);
247            stateset->addUniform(baseTextureSampler);
248        }
249
250
251        bool enableBlending = false;
252
253        if (tf)
254        {
255            float tfScale = 1.0f;
256            float tfOffset = 0.0f;
257
258            ImageLayer* imageLayer = dynamic_cast<ImageLayer*>(_volumeTile->getLayer());
259            if (imageLayer)
260            {
261                tfOffset = (imageLayer->getTexelOffset()[3] - tf->getMinimum()) / (tf->getMaximum() - tf->getMinimum());
262                tfScale = imageLayer->getTexelScale()[3] / (tf->getMaximum() - tf->getMinimum());
263            }
264            else
265            {
266                tfOffset = -tf->getMinimum() / (tf->getMaximum()-tf->getMinimum());
267                tfScale = 1.0f / (tf->getMaximum()-tf->getMinimum());
268            }
269            osg::ref_ptr<osg::Texture1D> tf_texture = new osg::Texture1D;
270            tf_texture->setImage(tf->getImage());
271
272            tf_texture->setResizeNonPowerOfTwoHint(false);
273            tf_texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
274            tf_texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
275            tf_texture->setWrap(osg::Texture::WRAP_R,osg::Texture::CLAMP_TO_EDGE);
276
277            stateset->setTextureAttributeAndModes(1, tf_texture.get(), osg::StateAttribute::ON);
278            stateset->addUniform(new osg::Uniform("tfTexture",1));
279            stateset->addUniform(new osg::Uniform("tfOffset",tfOffset));
280            stateset->addUniform(new osg::Uniform("tfScale",tfScale));
281
282        }
283
284        if (shadingModel==MaximumIntensityProjection)
285        {
286            enableBlending = true;
287
288            if (tf)
289            {
290                osg::Shader* fragmentShader = osgDB::readShaderFile(osg::Shader::FRAGMENT, "shaders/volume_tf_mip.frag");
291                if (fragmentShader)
292                {
293                    program->addShader(fragmentShader);
294                }
295                else
296                {
297                    #include "Shaders/volume_tf_mip_frag.cpp"
298                    program->addShader(new osg::Shader(osg::Shader::FRAGMENT, volume_tf_mip_frag));
299                }
300
301                osg::Uniform* tfTextureSampler = new osg::Uniform("tfTexture",1);
302                stateset->addUniform(tfTextureSampler);
303
304            }
305            else
306            {
307                osg::Shader* fragmentShader = osgDB::readShaderFile(osg::Shader::FRAGMENT, "shaders/volume_mip.frag");
308                if (fragmentShader)
309                {
310                    program->addShader(fragmentShader);
311                }
312                else
313                {
314                    #include "Shaders/volume_mip_frag.cpp"
315                    program->addShader(new osg::Shader(osg::Shader::FRAGMENT, volume_mip_frag));
316                }
317            }
318        }
319        else if (shadingModel==Isosurface)
320        {
321
322            enableBlending = true;
323
324            stateset->addUniform(cpv._isoProperty->getUniform());
325
326            if (tf)
327            {
328                osg::Shader* fragmentShader = osgDB::readShaderFile(osg::Shader::FRAGMENT, "shaders/volume_tf_iso.frag");
329                if (fragmentShader)
330                {
331                    program->addShader(fragmentShader);
332                }
333                else
334                {
335                    #include "Shaders/volume_tf_iso_frag.cpp"
336                    program->addShader(new osg::Shader(osg::Shader::FRAGMENT, volume_tf_iso_frag));
337                }
338            }
339            else
340            {
341                osg::Shader* fragmentShader = osgDB::readShaderFile(osg::Shader::FRAGMENT, "shaders/volume_iso.frag");
342                if (fragmentShader)
343                {
344                    OSG_INFO<<"Shader found"<<std::endl;
345
346                    program->addShader(fragmentShader);
347                }
348                else
349                {
350                    OSG_INFO<<"No Shader found"<<std::endl;
351
352                    #include "Shaders/volume_iso_frag.cpp"
353                    program->addShader(new osg::Shader(osg::Shader::FRAGMENT, volume_iso_frag));
354                }
355            }
356        }
357        else if (shadingModel==Light)
358        {
359            enableBlending = true;
360
361            if (tf)
362            {
363                osg::Shader* fragmentShader = osgDB::readShaderFile(osg::Shader::FRAGMENT, "shaders/volume_lit_tf.frag");
364                if (fragmentShader)
365                {
366                    program->addShader(fragmentShader);
367                }
368                else
369                {
370                    #include "Shaders/volume_lit_tf_frag.cpp"
371                    program->addShader(new osg::Shader(osg::Shader::FRAGMENT, volume_lit_tf_frag));
372                }
373
374            }
375            else
376            {
377                osg::Shader* fragmentShader = osgDB::readShaderFile(osg::Shader::FRAGMENT, "shaders/volume_lit.frag");
378                if (fragmentShader)
379                {
380                    program->addShader(fragmentShader);
381                }
382                else
383                {
384                    #include "Shaders/volume_lit_frag.cpp"
385                    program->addShader(new osg::Shader(osg::Shader::FRAGMENT, volume_lit_frag));
386                }
387            }
388        }
389        else
390        {
391            enableBlending = true;
392
393            if (tf)
394            {
395                osg::Shader* fragmentShader = osgDB::readShaderFile(osg::Shader::FRAGMENT, "shaders/volume_tf.frag");
396                if (fragmentShader)
397                {
398                    program->addShader(fragmentShader);
399                }
400                else
401                {
402                    #include "Shaders/volume_tf_frag.cpp"
403                    program->addShader(new osg::Shader(osg::Shader::FRAGMENT, volume_tf_frag));
404                }
405
406            }
407            else
408            {
409                osg::Shader* fragmentShader = osgDB::readShaderFile(osg::Shader::FRAGMENT, "shaders/volume.frag");
410                if (fragmentShader)
411                {
412                    program->addShader(fragmentShader);
413                }
414                else
415                {
416                    #include "Shaders/volume_frag.cpp"
417                    program->addShader(new osg::Shader(osg::Shader::FRAGMENT, volume_frag));
418                }
419            }
420        }
421
422        if (cpv._sampleDensityProperty.valid())
423            stateset->addUniform(cpv._sampleDensityProperty->getUniform());
424        else
425            stateset->addUniform(new osg::Uniform("SampleDensityValue",0.0005f));
426
427
428        if (cpv._transparencyProperty.valid())
429            stateset->addUniform(cpv._transparencyProperty->getUniform());
430        else
431            stateset->addUniform(new osg::Uniform("TransparencyValue",1.0f));
432
433
434        if (cpv._afProperty.valid())
435            stateset->addUniform(cpv._afProperty->getUniform());
436        else
437            stateset->addUniform(new osg::Uniform("AlphaFuncValue",alphaFuncValue));
438
439
440        if (enableBlending)
441        {
442            stateset->setMode(GL_BLEND, osg::StateAttribute::ON);
443            stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
444        }
445
446
447        stateset->setMode(GL_CULL_FACE, osg::StateAttribute::ON);
448
449        osg::TexGen* texgen = new osg::TexGen;
450        texgen->setMode(osg::TexGen::OBJECT_LINEAR);
451        texgen->setPlanesFromMatrix( geometryMatrix * osg::Matrix::inverse(imageMatrix));
452
453        if (masterLocator)
454        {
455            osg::ref_ptr<TexGenLocatorCallback> locatorCallback = new TexGenLocatorCallback(texgen, masterLocator, layerLocator);
456            masterLocator->addCallback(locatorCallback.get());
457            if (masterLocator != layerLocator)
458            {
459                if (layerLocator) layerLocator->addCallback(locatorCallback.get());
460            }
461        }
462
463        stateset->setTextureAttributeAndModes(0, texgen, osg::StateAttribute::ON);
464
465    }
466
467    {
468        osg::Geometry* geom = new osg::Geometry;
469
470        osg::Vec3Array* coords = new osg::Vec3Array(8);
471        (*coords)[0] = osg::Vec3d(0.0,0.0,0.0);
472        (*coords)[1] = osg::Vec3d(1.0,0.0,0.0);
473        (*coords)[2] = osg::Vec3d(1.0,1.0,0.0);
474        (*coords)[3] = osg::Vec3d(0.0,1.0,0.0);
475        (*coords)[4] = osg::Vec3d(0.0,0.0,1.0);
476        (*coords)[5] = osg::Vec3d(1.0,0.0,1.0);
477        (*coords)[6] = osg::Vec3d(1.0,1.0,1.0);
478        (*coords)[7] = osg::Vec3d(0.0,1.0,1.0);
479        geom->setVertexArray(coords);
480
481        osg::Vec4Array* colours = new osg::Vec4Array(1);
482        (*colours)[0].set(1.0f,1.0f,1.0,1.0f);
483        geom->setColorArray(colours);
484        geom->setColorBinding(osg::Geometry::BIND_OVERALL);
485
486        osg::DrawElementsUShort* drawElements = new osg::DrawElementsUShort(GL_QUADS);
487        // bottom
488        drawElements->push_back(0);
489        drawElements->push_back(1);
490        drawElements->push_back(2);
491        drawElements->push_back(3);
492
493        // bottom
494        drawElements->push_back(3);
495        drawElements->push_back(2);
496        drawElements->push_back(6);
497        drawElements->push_back(7);
498
499        // left
500        drawElements->push_back(0);
501        drawElements->push_back(3);
502        drawElements->push_back(7);
503        drawElements->push_back(4);
504
505        // right
506        drawElements->push_back(5);
507        drawElements->push_back(6);
508        drawElements->push_back(2);
509        drawElements->push_back(1);
510
511        // front
512        drawElements->push_back(1);
513        drawElements->push_back(0);
514        drawElements->push_back(4);
515        drawElements->push_back(5);
516
517        // top
518        drawElements->push_back(7);
519        drawElements->push_back(6);
520        drawElements->push_back(5);
521        drawElements->push_back(4);
522
523        geom->addPrimitiveSet(drawElements);
524
525        geode->addDrawable(geom);
526
527    }
528
529    if (cpv._sampleDensityWhenMovingProperty.valid())
530    {
531        _whenMovingStateSet = new osg::StateSet;
532        _whenMovingStateSet->addUniform(cpv._sampleDensityWhenMovingProperty->getUniform(), osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);
533    }
534}
535
536void RayTracedTechnique::update(osgUtil::UpdateVisitor* uv)
537{
538//    OSG_NOTICE<<"RayTracedTechnique:update(osgUtil::UpdateVisitor* nv):"<<std::endl;
539}
540
541void RayTracedTechnique::cull(osgUtil::CullVisitor* cv)
542{
543    if (!_transform.valid()) return;
544
545    if (_whenMovingStateSet.valid())
546    {
547        bool moving = false;
548        {
549            OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
550            ModelViewMatrixMap::iterator itr = _modelViewMatrixMap.find(cv->getIdentifier());
551            if (itr!=_modelViewMatrixMap.end())
552            {
553                osg::Matrix newModelViewMatrix = *(cv->getModelViewMatrix());
554                osg::Matrix& previousModelViewMatrix = itr->second;
555                moving = (newModelViewMatrix != previousModelViewMatrix);
556
557                previousModelViewMatrix = newModelViewMatrix;
558            }
559            else
560            {
561                _modelViewMatrixMap[cv->getIdentifier()] = *(cv->getModelViewMatrix());
562            }
563        }
564
565        if (moving)
566        {
567            cv->pushStateSet(_whenMovingStateSet.get());
568            _transform->accept(*cv);
569            cv->popStateSet();
570        }
571        else
572        {
573            _transform->accept(*cv);
574        }
575    }
576    else
577    {
578        _transform->accept(*cv);
579    }
580}
581
582void RayTracedTechnique::cleanSceneGraph()
583{
584    OSG_NOTICE<<"RayTracedTechnique::cleanSceneGraph()"<<std::endl;
585}
586
587void RayTracedTechnique::traverse(osg::NodeVisitor& nv)
588{
589    // OSG_NOTICE<<"RayTracedTechnique::traverse(osg::NodeVisitor& nv)"<<std::endl;
590    if (!_volumeTile) return;
591
592    // if app traversal update the frame count.
593    if (nv.getVisitorType()==osg::NodeVisitor::UPDATE_VISITOR)
594    {
595        if (_volumeTile->getDirty()) _volumeTile->init();
596
597        osgUtil::UpdateVisitor* uv = dynamic_cast<osgUtil::UpdateVisitor*>(&nv);
598        if (uv)
599        {
600            update(uv);
601            return;
602        }
603
604    }
605    else if (nv.getVisitorType()==osg::NodeVisitor::CULL_VISITOR)
606    {
607        osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(&nv);
608        if (cv)
609        {
610            cull(cv);
611            return;
612        }
613    }
614
615
616    if (_volumeTile->getDirty())
617    {
618        OSG_INFO<<"******* Doing init ***********"<<std::endl;
619        _volumeTile->init();
620    }
621}
622
623
624} // end of osgVolume namespace
Note: See TracBrowser for help on using the browser.