root/OpenSceneGraph/trunk/examples/osgvertexattributes/osgvertexattributes.cpp @ 13342

Revision 12292, 17.9 kB (checked in by robert, 4 years ago)

Ran svn propset -R svn:eol-style native . on the OpenSceneGraph

  • Property svn:eol-style set to native
Line 
1/* OpenSceneGraph example, osgvertexattributes.
2*
3*  Permission is hereby granted, free of charge, to any person obtaining a copy
4*  of this software and associated documentation files (the "Software"), to deal
5*  in the Software without restriction, including without limitation the rights
6*  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7*  copies of the Software, and to permit persons to whom the Software is
8*  furnished to do so, subject to the following conditions:
9*
10*  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
11*  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12*  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
13*  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
14*  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
15*  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
16*  THE SOFTWARE.
17*/
18
19#include <osgUtil/ShaderGen>
20#include <osgDB/ReadFile>
21#include <osgDB/WriteFile>
22#include <osgViewer/Viewer>
23#include <osgViewer/ViewerEventHandlers>
24#include <osgGA/TrackballManipulator>
25
26class ConvertToVertexAttibArrays : public osg::NodeVisitor
27{
28    public:
29
30        typedef std::pair<unsigned int, std::string> AttributeAlias;
31
32        ConvertToVertexAttibArrays():
33            osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
34        {
35            _manualVertexAliasing = false;
36
37            // mappings taken from http://www.opengl.org/registry/specs/NV/vertex_program.txt
38            _vertexAlias = AttributeAlias(0, "osg_Vertex");
39            _normalAlias = AttributeAlias(2, "osg_Normal");
40            _colorAlias = AttributeAlias(3, "osg_Color");
41            _secondaryColorAlias = AttributeAlias(4, "osg_SecondaryColor");
42            _fogCoordAlias = AttributeAlias(5, "osg_FogCoord");
43            _texCoordAlias[0] = AttributeAlias(8, "osg_MultiTexCoord0");
44            _texCoordAlias[1] = AttributeAlias(9, "osg_MultiTexCoord1");
45            _texCoordAlias[2] = AttributeAlias(10, "osg_MultiTexCoord2");
46            _texCoordAlias[3] = AttributeAlias(11, "osg_MultiTexCoord3");
47            _texCoordAlias[4] = AttributeAlias(12, "osg_MultiTexCoord4");
48            _texCoordAlias[5] = AttributeAlias(13, "osg_MultiTexCoord5");
49            _texCoordAlias[6] = AttributeAlias(14, "osg_MultiTexCoord6");
50            _texCoordAlias[7] = AttributeAlias(15, "osg_MultiTexCoord7");
51        }
52
53        void bindAttribute(osg::Program& program, const AttributeAlias& alias)
54        {
55                program.addBindAttribLocation(alias.second, alias.first);
56        }
57
58        void replaceAndBindAttrib(osg::Program& program, std::string& source, const std::string& originalStr, const AttributeAlias& alias, const std::string& declarationPrefix)
59        {
60            if (replace(source, originalStr, alias.second))
61            {
62                source.insert(0, declarationPrefix + alias.second + std::string(";\n"));
63                if (_manualVertexAliasing) bindAttribute(program, alias);
64            }
65        }
66
67        void replaceBuiltInUniform(std::string& source, const std::string& originalStr, const std::string& newStr, const std::string& declarationPrefix)
68        {
69            if (replace(source, originalStr, newStr))
70            {
71                source.insert(0, declarationPrefix + newStr + std::string(";\n"));
72            }
73        }
74
75        void convertVertexShader(osg::Program& program, osg::Shader& shader)
76        {
77            std::string source = shader.getShaderSource();
78
79            // replace ftransform as it only works with built-ins
80            replace(source, "ftransform()", "gl_ModelViewProjectionMatrix * gl_Vertex");
81
82#if 1
83            replaceAndBindAttrib(program, source, "gl_Normal", _normalAlias, "attribute vec3 ");
84            replaceAndBindAttrib(program, source, "gl_Vertex", _vertexAlias, "attribute vec4 ");
85            replaceAndBindAttrib(program, source, "gl_Color", _colorAlias, "attribute vec4 ");
86            replaceAndBindAttrib(program, source, "gl_SecondaryColor", _secondaryColorAlias, "attribute vec4 ");
87            replaceAndBindAttrib(program, source, "gl_FogCoord", _fogCoordAlias, "attribute float ");
88
89            replaceAndBindAttrib(program, source, "gl_MultiTexCoord0", _texCoordAlias[0], "attribute vec4 ");
90            replaceAndBindAttrib(program, source, "gl_MultiTexCoord1", _texCoordAlias[1], "attribute vec4 ");
91            replaceAndBindAttrib(program, source, "gl_MultiTexCoord2", _texCoordAlias[2], "attribute vec4 ");
92            replaceAndBindAttrib(program, source, "gl_MultiTexCoord3", _texCoordAlias[3], "attribute vec4 ");
93            replaceAndBindAttrib(program, source, "gl_MultiTexCoord4", _texCoordAlias[4], "attribute vec4 ");
94            replaceAndBindAttrib(program, source, "gl_MultiTexCoord5", _texCoordAlias[5], "attribute vec4 ");
95            replaceAndBindAttrib(program, source, "gl_MultiTexCoord6", _texCoordAlias[6], "attribute vec4 ");
96            replaceAndBindAttrib(program, source, "gl_MultiTexCoord7", _texCoordAlias[7], "attribute vec4 ");
97#endif
98
99#if 1
100            // replace built in uniform
101            replaceBuiltInUniform(source, "gl_ModelViewMatrix", "osg_ModeViewMatrix", "uniform mat4 ");
102            replaceBuiltInUniform(source, "gl_ModelViewProjectionMatrix", "osg_ModelViewProjectionMatrix", "uniform mat4 ");
103            replaceBuiltInUniform(source, "gl_ProjectionMatrix", "osg_ProjectionMatrix", "uniform mat4 ");
104#endif
105            shader.setShaderSource(source);
106        }
107
108        void convertFragmentShader(osg::Program& program, osg::Shader& shader)
109        {
110        }
111
112        virtual void reset()
113        {
114            _visited.clear();
115        }
116
117        void apply(osg::Node& node)
118        {
119            if (_visited.count(&node)!=0) return;
120            _visited.insert(&node);
121
122            if (node.getStateSet()) apply(*(node.getStateSet()));
123            traverse(node);
124        }
125
126        void apply(osg::Geode& geode)
127        {
128            if (_visited.count(&geode)!=0) return;
129            _visited.insert(&geode);
130
131            if (geode.getStateSet()) apply(*(geode.getStateSet()));
132
133            for(unsigned int i=0; i<geode.getNumDrawables(); ++i)
134            {
135                if (geode.getDrawable(i)->getStateSet()) apply(*(geode.getDrawable(i)->getStateSet()));
136
137                osg::Geometry* geom = geode.getDrawable(i)->asGeometry();
138                if (geom) apply(*geom);
139            }
140        }
141
142        bool replace(std::string& str, const std::string& original_phrase, const std::string& new_phrase)
143        {
144            bool replacedStr = false;
145            std::string::size_type pos = 0;
146            while((pos=str.find(original_phrase, pos))!=std::string::npos)
147            {
148                std::string::size_type endOfPhrasePos = pos+original_phrase.size();
149                if (endOfPhrasePos<str.size())
150                {
151                    char c = str[endOfPhrasePos];
152                    if ((c>='0' && c<='9') ||
153                        (c>='a' && c<='z') ||
154                        (c>='A' && c<='Z'))
155                    {
156                        pos = endOfPhrasePos;
157                        continue;
158                    }
159                }
160
161                replacedStr = true;
162                str.replace(pos, original_phrase.size(), new_phrase);
163            }
164            return replacedStr;
165        }
166
167        void apply(osg::Program& program, osg::Shader& shader)
168        {
169             if (_visited.count(&shader)!=0) return;
170            _visited.insert(&shader);
171
172            osg::notify(osg::NOTICE)<<"Shader "<<shader.getTypename()<<" ----before-----------"<<std::endl;
173            osg::notify(osg::NOTICE)<<shader.getShaderSource()<<std::endl;
174
175            if (shader.getType()==osg::Shader::VERTEX) convertVertexShader(program, shader);
176            else if (shader.getType()==osg::Shader::FRAGMENT) convertFragmentShader(program, shader);
177
178            osg::notify(osg::NOTICE)<<"--after-----------"<<std::endl;
179            osg::notify(osg::NOTICE)<<shader.getShaderSource()<<std::endl;
180            osg::notify(osg::NOTICE)<<"---------------------"<<std::endl;
181        }
182
183        void apply(osg::StateSet& stateset)
184        {
185             if (_visited.count(&stateset)!=0) return;
186            _visited.insert(&stateset);
187
188            return;
189
190            osg::notify(osg::NOTICE)<<"Found stateset "<<&stateset<<std::endl;
191            osg::Program* program = dynamic_cast<osg::Program*>(stateset.getAttribute(osg::StateAttribute::PROGRAM));
192            if (program)
193            {
194                osg::notify(osg::NOTICE)<<"   Found Program "<<program<<std::endl;
195                for(unsigned int i=0; i<program->getNumShaders(); ++i)
196                {
197                    apply(*program, *(program->getShader(i)));
198                }
199
200            }
201       }
202
203        void apply(osg::Geometry& geom)
204        {
205            geom.setUseDisplayList(false);
206
207            if (!_manualVertexAliasing) return;
208
209            osg::notify(osg::NOTICE)<<"Found geometry "<<&geom<<std::endl;
210            if (geom.getVertexArray())
211            {
212                setVertexAttrib(geom, _vertexAlias, geom.getVertexArray(), false, osg::Geometry::BIND_PER_VERTEX);
213                geom.setVertexArray(0);
214            }
215
216            if (geom.getNormalArray())
217            {
218                setVertexAttrib(geom, _normalAlias, geom.getNormalArray(), true, geom.getNormalBinding());
219                geom.setNormalArray(0);
220            }
221
222            if (geom.getColorArray())
223            {
224                setVertexAttrib(geom, _colorAlias, geom.getColorArray(), false, geom.getColorBinding());
225                geom.setColorArray(0);
226            }
227
228            if (geom.getSecondaryColorArray())
229            {
230                setVertexAttrib(geom, _secondaryColorAlias, geom.getSecondaryColorArray(), false, geom.getSecondaryColorBinding());
231                geom.setSecondaryColorArray(0);
232            }
233
234            if (geom.getFogCoordArray())
235            {
236                // should we normalize the FogCoord array? Don't think so...
237                setVertexAttrib(geom, _fogCoordAlias, geom.getFogCoordArray(), false, geom.getFogCoordBinding());
238                geom.setFogCoordArray(0);
239            }
240
241            unsigned int maxNumTexCoords = geom.getNumTexCoordArrays();
242            if (maxNumTexCoords>8)
243            {
244                osg::notify(osg::NOTICE)<<"Warning: Ignoring "<<maxNumTexCoords-8<<" texture coordinate arrays, only 8 are currently supported in vertex attribute conversion code."<<std::endl;
245                maxNumTexCoords = 8;
246            }
247            for(unsigned int i=0; i<maxNumTexCoords; ++i)
248            {
249                if (geom.getTexCoordArray(i))
250                {
251                    setVertexAttrib(geom, _texCoordAlias[i], geom.getTexCoordArray(i), false, osg::Geometry::BIND_PER_VERTEX);
252                    geom.setTexCoordArray(i,0);
253                }
254                else
255                {
256                    osg::notify(osg::NOTICE)<<"Found empty TexCoordArray("<<i<<")"<<std::endl;
257                }
258            }
259        }
260
261        void setVertexAttrib(osg::Geometry& geom, const AttributeAlias& alias, osg::Array* array, bool normalize, osg::Geometry::AttributeBinding binding)
262        {
263            unsigned int index = alias.first;
264            const std::string& name = alias.second;
265            array->setName(name);
266            geom.setVertexAttribArray(index, array);
267            geom.setVertexAttribNormalize(index, normalize);
268            geom.setVertexAttribBinding(index, binding);
269
270            osg::notify(osg::NOTICE)<<"   vertex attrib("<<name<<", index="<<index<<", normalize="<<normalize<<" binding="<<binding<<")"<<std::endl;
271        }
272
273
274        typedef std::set<osg::Object*> Visited;
275        Visited         _visited;
276
277        bool           _manualVertexAliasing;
278        AttributeAlias _vertexAlias;
279        AttributeAlias _normalAlias;
280        AttributeAlias _colorAlias;
281        AttributeAlias _secondaryColorAlias;
282        AttributeAlias _fogCoordAlias;
283        AttributeAlias _texCoordAlias[8];
284};
285
286osg::Node* createSimpleTestModel()
287{
288    osg::Group* group = new osg::Group;
289   
290    osg::Geode* geode = new osg::Geode;
291    group->addChild(geode);
292   
293    osg::Geometry* geometry = new osg::Geometry;
294    geode->addDrawable(geometry);
295
296    osg::Vec3Array* vertices = new osg::Vec3Array;
297    vertices->push_back(osg::Vec3(0.0,0.0,0.0));
298    vertices->push_back(osg::Vec3(0.0,0.0,1.0));
299    vertices->push_back(osg::Vec3(1.0,0.0,0.0));
300    vertices->push_back(osg::Vec3(1.0,0.0,1.0));
301    geometry->setVertexArray(vertices);
302
303    geometry->addPrimitiveSet(new osg::DrawArrays(GL_TRIANGLE_STRIP, 0, 4));
304   
305    char vertexShaderSource[] =
306       "void main(void)\n"
307       "{\n"
308       "    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
309       "}\n";
310
311    char fragmentShaderSource[] =
312        "void main(void)\n"
313        "{\n"
314        "    gl_FragColor = vec4(1.0,1.0,0.0,1.0); \n"
315        "}\n";
316
317    osg::Program* program = new osg::Program;
318    program->addShader(new osg::Shader(osg::Shader::VERTEX, vertexShaderSource));
319    program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource));
320
321    geometry->getOrCreateStateSet()->setAttribute(program);
322   
323    return group;
324}
325
326osg::Node* createSimpleTextureTestModel()
327{
328    osg::Group* group = new osg::Group;
329   
330    osg::Geode* geode = new osg::Geode;
331    group->addChild(geode);
332   
333    osg::Geometry* geometry = new osg::Geometry;
334    geode->addDrawable(geometry);
335
336    osg::Vec3Array* vertices = new osg::Vec3Array;
337    vertices->push_back(osg::Vec3(0.0,0.0,0.0));
338    vertices->push_back(osg::Vec3(0.0,0.0,1.0));
339    vertices->push_back(osg::Vec3(1.0,0.0,0.0));
340    vertices->push_back(osg::Vec3(1.0,0.0,1.0));
341    geometry->setVertexArray(vertices);
342
343    osg::Vec2Array* texcoords = new osg::Vec2Array;
344    texcoords->push_back(osg::Vec2(0.0,0.0));
345    texcoords->push_back(osg::Vec2(0.0,1.0));
346    texcoords->push_back(osg::Vec2(1.0,0.0));
347    texcoords->push_back(osg::Vec2(1.0,1.0));
348    geometry->setTexCoordArray(0, texcoords);
349
350    geometry->addPrimitiveSet(new osg::DrawArrays(GL_TRIANGLE_STRIP, 0, 4));
351   
352    char vertexShaderSource[] =
353       "varying vec2 texCoord;\n"
354       "void main(void)\n"
355       "{\n"
356       "    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
357       "    texCoord = gl_MultiTexCoord0.xy;\n"
358       "}\n";
359
360    char fragmentShaderSource[] =
361        "varying vec2 texCoord;\n"
362        "uniform sampler2D baseTexture;\n"
363        "void main(void)\n"
364        "{\n"
365        "    gl_FragColor = texture2D(baseTexture, texCoord); \n"
366        "}\n";
367
368    osg::Program* program = new osg::Program;
369    program->addShader(new osg::Shader(osg::Shader::VERTEX, vertexShaderSource));
370    program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource));
371
372    osg::StateSet* stateset = geometry->getOrCreateStateSet();
373    stateset->setAttribute(program);
374   
375    osg::Image* image = osgDB::readImageFile("Images/lz.rgb");
376    osg::Texture2D* texture = new osg::Texture2D(image);
377    texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
378    texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
379    stateset->setTextureAttribute(0, texture);
380   
381    osg::Uniform* baseTextureSampler = new osg::Uniform("baseTexture",0);
382    stateset->addUniform(baseTextureSampler);
383
384    return group;
385}
386
387int main(int argc, char *argv[])
388{
389    // use an ArgumentParser object to manage the program arguments.
390    osg::ArgumentParser arguments(&argc,argv);
391
392    // construct the viewer.
393    osgViewer::Viewer viewer(arguments);
394
395    std::string outputFileName;
396    while (arguments.read("-o",outputFileName)) {}
397
398    osg::ref_ptr<osg::Node> loadedModel;
399
400    bool runConvertToVertexAttributes = false;
401    if (arguments.read("--simple") || arguments.read("--s"))
402    {
403        loadedModel = createSimpleTestModel();
404    }
405    else if (arguments.read("--texture") || arguments.read("-t"))
406    {
407        loadedModel = createSimpleTextureTestModel();
408    }
409    else
410    {
411        bool runShaderGen = true;
412        while (arguments.read("--shader-gen")) { runShaderGen = true; }
413        while (arguments.read("--no-shader-gen")) { runShaderGen = false; }
414
415        while (arguments.read("--vertex-attrib")) { runConvertToVertexAttributes = true; }
416        while (arguments.read("--no-vertex-attrib")) { runConvertToVertexAttributes = false; }
417
418        loadedModel = osgDB::readNodeFiles(arguments);
419        if (!loadedModel.get())
420        {
421            osg::notify(osg::NOTICE)<<"No model loaded, please specify a model filename."<<std::endl;
422            return 1;
423        }
424
425        if (runShaderGen)
426        {
427            // convert fixed function pipeline to shaders
428            osgUtil::ShaderGenVisitor sgv;
429            loadedModel->accept(sgv);
430        }
431
432        if (runConvertToVertexAttributes)
433        {
434            // find any conventional vertex, colour, normal and tex coords arrays and convert to vertex attributes
435            ConvertToVertexAttibArrays ctvaa;
436            loadedModel->accept(ctvaa);
437        }
438    }
439   
440    if (!loadedModel) return 1;
441   
442    if (!outputFileName.empty())
443    {
444        osgDB::writeNodeFile(*loadedModel, outputFileName);
445        return 0;
446    }
447
448    // add a viewport to the viewer and attach the scene graph.
449    viewer.setSceneData(loadedModel.get());
450
451    viewer.setCameraManipulator(new osgGA::TrackballManipulator());
452
453    // add the stats handler
454    viewer.addEventHandler(new osgViewer::StatsHandler);
455
456    viewer.realize();
457
458
459    if (runConvertToVertexAttributes)
460    {
461        // switch on the uniforms that track the modelview and projection matrices
462        osgViewer::Viewer::Windows windows;
463        viewer.getWindows(windows);
464        for(osgViewer::Viewer::Windows::iterator itr = windows.begin();
465            itr != windows.end();
466            ++itr)
467        {
468            (*itr)->getState()->setUseModelViewAndProjectionUniforms(true);
469            (*itr)->getState()->setUseVertexAttributeAliasing(true);
470        }
471    }
472
473    return viewer.run();
474}
Note: See TracBrowser for help on using the browser.