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

Revision 10641, 14.0 kB (checked in by robert, 5 years ago)

Made the use of the new projection and modelview matrix uniforms optional

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 <osgGA/TrackballManipulator>
24
25class ConvertToVertexAttibArrays : public osg::NodeVisitor
26{
27    public:
28
29        typedef std::pair<unsigned int, std::string> AttributeAlias;
30
31        ConvertToVertexAttibArrays():
32            osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
33        {
34            // mappings taken from http://www.opengl.org/registry/specs/NV/vertex_program.txt
35            _vertexAlias = AttributeAlias(0, "osg_Vertex");
36            _normalAlias = AttributeAlias(2, "osg_Normal");
37            _colorAlias = AttributeAlias(3, "osg_Color");
38            _secondaryColorAlias = AttributeAlias(4, "osg_SecondaryColor");
39            _fogCoordAlias = AttributeAlias(5, "osg_FogCoord");
40            _texCoordAlias[0] = AttributeAlias(8, "osg_MultiTexCoord0");
41            _texCoordAlias[1] = AttributeAlias(9, "osg_MultiTexCoord1");
42            _texCoordAlias[2] = AttributeAlias(10, "osg_MultiTexCoord2");
43            _texCoordAlias[3] = AttributeAlias(11, "osg_MultiTexCoord3");
44            _texCoordAlias[4] = AttributeAlias(12, "osg_MultiTexCoord4");
45            _texCoordAlias[5] = AttributeAlias(13, "osg_MultiTexCoord5");
46            _texCoordAlias[6] = AttributeAlias(14, "osg_MultiTexCoord6");
47            _texCoordAlias[7] = AttributeAlias(15, "osg_MultiTexCoord7");
48        }
49
50        void bindAttribute(osg::Program& program, const AttributeAlias& alias)
51        {
52                program.addBindAttribLocation(alias.second, alias.first);
53        }
54
55        void replaceAndBindAttrib(osg::Program& program, std::string& source, const std::string& originalStr, const AttributeAlias& alias, const std::string& declarationPrefix)
56        {
57            if (replace(source, originalStr, alias.second))
58            {
59                source.insert(0, declarationPrefix + alias.second + std::string(";\n"));
60                bindAttribute(program, alias);
61            }
62        }
63
64        void replaceBuiltInUniform(std::string& source, const std::string& originalStr, const std::string& newStr, const std::string& declarationPrefix)
65        {
66            if (replace(source, originalStr, newStr))
67            {
68                source.insert(0, declarationPrefix + newStr + std::string(";\n"));
69            }
70        }
71
72        void convertVertexShader(osg::Program& program, osg::Shader& shader)
73        {
74            std::string source = shader.getShaderSource();
75
76            // replace ftransform as it only works with built-ins
77            replace(source, "ftransform()", "gl_ModelViewProjectionMatrix * gl_Vertex");
78
79            replaceAndBindAttrib(program, source, "gl_Normal", _normalAlias, "attribute vec3 ");
80            replaceAndBindAttrib(program, source, "gl_Vertex", _vertexAlias, "attribute vec4 ");
81            replaceAndBindAttrib(program, source, "gl_Color", _colorAlias, "attribute vec4 ");
82            replaceAndBindAttrib(program, source, "gl_SecondaryColor", _secondaryColorAlias, "attribute vec4 ");
83            replaceAndBindAttrib(program, source, "gl_FogCoord", _fogCoordAlias, "attribute float ");
84
85            replaceAndBindAttrib(program, source, "gl_MultiTexCoord0", _texCoordAlias[0], "attribute vec4 ");
86            replaceAndBindAttrib(program, source, "gl_MultiTexCoord1", _texCoordAlias[1], "attribute vec4 ");
87            replaceAndBindAttrib(program, source, "gl_MultiTexCoord2", _texCoordAlias[2], "attribute vec4 ");
88            replaceAndBindAttrib(program, source, "gl_MultiTexCoord3", _texCoordAlias[3], "attribute vec4 ");
89            replaceAndBindAttrib(program, source, "gl_MultiTexCoord4", _texCoordAlias[4], "attribute vec4 ");
90            replaceAndBindAttrib(program, source, "gl_MultiTexCoord5", _texCoordAlias[5], "attribute vec4 ");
91            replaceAndBindAttrib(program, source, "gl_MultiTexCoord6", _texCoordAlias[6], "attribute vec4 ");
92            replaceAndBindAttrib(program, source, "gl_MultiTexCoord7", _texCoordAlias[7], "attribute vec4 ");
93
94
95#if 0
96            // replace the modelview and project matrices
97            replace(source, "gl_ModelViewMatrix", "osg_ModeViewMatrix");
98            replace(source, "gl_ModelViewProjectionMatrix", "osg_ModelViewProjectionMatrix");
99            replace(source, "gl_ProjectionMatrix", "osg_ProjectionMatrix");
100#else
101            // replace built in uniform
102            replaceBuiltInUniform(source, "gl_ModelViewMatrix", "osg_ModeViewMatrix", "uniform mat4 ");
103            replaceBuiltInUniform(source, "gl_ModelViewProjectionMatrix", "osg_ModelViewProjectionMatrix", "uniform mat4 ");
104            replaceBuiltInUniform(source, "gl_ProjectionMatrix", "osg_ProjectionMatrix", "uniform mat4 ");
105#endif
106            shader.setShaderSource(source);
107        }
108
109        void convertFragmentShader(osg::Program& program, osg::Shader& shader)
110        {
111        }
112
113        virtual void reset()
114        {
115            _visited.clear();
116        }
117
118        void apply(osg::Node& node)
119        {
120            if (_visited.count(&node)!=0) return;
121            _visited.insert(&node);
122
123            if (node.getStateSet()) apply(*(node.getStateSet()));
124            traverse(node);
125        }
126
127        void apply(osg::Geode& geode)
128        {
129            if (_visited.count(&geode)!=0) return;
130            _visited.insert(&geode);
131
132            if (geode.getStateSet()) apply(*(geode.getStateSet()));
133
134            for(unsigned int i=0; i<geode.getNumDrawables(); ++i)
135            {
136                if (geode.getDrawable(i)->getStateSet()) apply(*(geode.getDrawable(i)->getStateSet()));
137
138                osg::Geometry* geom = geode.getDrawable(i)->asGeometry();
139                if (geom) apply(*geom);
140            }
141        }
142
143        bool replace(std::string& str, const std::string& original_phrase, const std::string& new_phrase)
144        {
145            bool replacedStr = false;
146            std::string::size_type pos = 0;
147            while((pos=str.find(original_phrase, pos))!=std::string::npos)
148            {
149                std::string::size_type endOfPhrasePos = pos+original_phrase.size();
150                if (endOfPhrasePos<str.size())
151                {
152                    char c = str[endOfPhrasePos];
153                    if ((c>='0' && c<='9') ||
154                        (c>='a' && c<='z') ||
155                        (c>='A' && c<='Z'))
156                    {
157                        pos = endOfPhrasePos;
158                        continue;
159                    }
160                }
161
162                replacedStr = true;
163                str.replace(pos, original_phrase.size(), new_phrase);
164            }
165            return replacedStr;
166        }
167
168        void apply(osg::Program& program, osg::Shader& shader)
169        {
170             if (_visited.count(&shader)!=0) return;
171            _visited.insert(&shader);
172
173            osg::notify(osg::NOTICE)<<"Shader "<<shader.getTypename()<<" ----before-----------"<<std::endl;
174            osg::notify(osg::NOTICE)<<shader.getShaderSource()<<std::endl;
175
176            if (shader.getType()==osg::Shader::VERTEX) convertVertexShader(program, shader);
177            else if (shader.getType()==osg::Shader::FRAGMENT) convertFragmentShader(program, shader);
178
179            osg::notify(osg::NOTICE)<<"--after-----------"<<std::endl;
180            osg::notify(osg::NOTICE)<<shader.getShaderSource()<<std::endl;
181            osg::notify(osg::NOTICE)<<"---------------------"<<std::endl;
182        }
183
184        void apply(osg::StateSet& stateset)
185        {
186             if (_visited.count(&stateset)!=0) return;
187            _visited.insert(&stateset);
188
189            osg::notify(osg::NOTICE)<<"Found stateset "<<&stateset<<std::endl;
190            osg::Program* program = dynamic_cast<osg::Program*>(stateset.getAttribute(osg::StateAttribute::PROGRAM));
191            if (program)
192            {
193                osg::notify(osg::NOTICE)<<"   Found Program "<<program<<std::endl;
194                for(unsigned int i=0; i<program->getNumShaders(); ++i)
195                {
196                    apply(*program, *(program->getShader(i)));
197                }
198
199            }
200       }
201
202        void apply(osg::Geometry& geom)
203        {
204            geom.setUseDisplayList(false);
205
206            osg::notify(osg::NOTICE)<<"Found geometry "<<&geom<<std::endl;
207            if (geom.getVertexArray())
208            {
209                setVertexAttrib(geom, _vertexAlias, geom.getVertexArray(), false, osg::Geometry::BIND_PER_VERTEX);
210                geom.setVertexArray(0);
211            }
212
213            if (geom.getNormalArray())
214            {
215                setVertexAttrib(geom, _normalAlias, geom.getNormalArray(), false, geom.getNormalBinding());
216                geom.setNormalArray(0);
217            }
218
219            if (geom.getColorArray())
220            {
221                setVertexAttrib(geom, _colorAlias, geom.getColorArray(), false, geom.getColorBinding());
222                geom.setColorArray(0);
223            }
224
225            if (geom.getSecondaryColorArray())
226            {
227                setVertexAttrib(geom, _secondaryColorAlias, geom.getSecondaryColorArray(), false, geom.getSecondaryColorBinding());
228                geom.setSecondaryColorArray(0);
229            }
230
231            if (geom.getFogCoordArray())
232            {
233                // should we normalize the FogCoord array? Don't think so...
234                setVertexAttrib(geom, _fogCoordAlias, geom.getFogCoordArray(), false, geom.getSecondaryColorBinding());
235                geom.setFogCoordArray(0);
236            }
237
238            unsigned int maxNumTexCoords = geom.getNumTexCoordArrays();
239            if (maxNumTexCoords>8)
240            {
241                osg::notify(osg::NOTICE)<<"Warning: Ignoring "<<maxNumTexCoords-8<<" texture coordinate arrays, only 8 are currently supported in vertex attribute conversion code."<<std::endl;
242                maxNumTexCoords = 8;
243            }
244            for(unsigned int i=0; i<maxNumTexCoords; ++i)
245            {
246                if (geom.getTexCoordArray(i))
247                {
248                    setVertexAttrib(geom, _texCoordAlias[i], geom.getTexCoordArray(i), false, osg::Geometry::BIND_PER_VERTEX);
249                    geom.setTexCoordArray(i,0);
250                }
251                else
252                {
253                    osg::notify(osg::NOTICE)<<"Found empty TexCoordArray("<<i<<")"<<std::endl;
254                }
255            }
256        }
257
258        void setVertexAttrib(osg::Geometry& geom, const AttributeAlias& alias, osg::Array* array, bool normalize, osg::Geometry::AttributeBinding binding)
259        {
260            unsigned int index = alias.first;
261            const std::string& name = alias.second;
262            array->setName(name);
263            geom.setVertexAttribArray(index, array);
264            geom.setVertexAttribNormalize(index, normalize);
265            geom.setVertexAttribBinding(index, binding);
266
267            osg::notify(osg::NOTICE)<<"   vertex attrib("<<name<<", index="<<index<<", normalize="<<normalize<<" binding="<<binding<<")"<<std::endl;
268        }
269
270
271        typedef std::set<osg::Object*> Visited;
272        Visited         _visited;
273
274        AttributeAlias _vertexAlias;
275        AttributeAlias _normalAlias;
276        AttributeAlias _colorAlias;
277        AttributeAlias _secondaryColorAlias;
278        AttributeAlias _fogCoordAlias;
279        AttributeAlias _texCoordAlias[8];
280};
281
282
283
284int main(int argc, char *argv[])
285{
286    // use an ArgumentParser object to manage the program arguments.
287    osg::ArgumentParser arguments(&argc,argv);
288
289    // construct the viewer.
290    osgViewer::Viewer viewer(arguments);
291
292    std::string outputFileName;
293    while (arguments.read("-o",outputFileName)) {}
294
295    bool runShaderGen = true;
296    while (arguments.read("--shader-gen")) { runShaderGen = true; }
297    while (arguments.read("--no-shader-gen")) { runShaderGen = false; }
298
299    bool runConvertToVertexAttributes = true;
300    while (arguments.read("--vertex-attrib")) { runConvertToVertexAttributes = true; }
301    while (arguments.read("--no-vertex-attrib")) { runConvertToVertexAttributes = false; }
302
303    osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFiles(arguments);
304    if (!loadedModel.get())
305    {
306        osg::notify(osg::NOTICE)<<"No model loaded, please specify a model filename."<<std::endl;
307        return 1;
308    }
309
310    if (runShaderGen)
311    {
312        // convert fixed function pipeline to shaders
313        osgUtil::ShaderGenVisitor sgv;
314        loadedModel->accept(sgv);
315    }
316
317    if (runConvertToVertexAttributes)
318    {
319        // find any conventional vertex, colour, normal and tex coords arrays and convert to vertex attributes
320        ConvertToVertexAttibArrays ctvaa;
321        loadedModel->accept(ctvaa);
322    }
323
324    if (!outputFileName.empty())
325    {
326        osgDB::writeNodeFile(*loadedModel, outputFileName);
327        return 0;
328    }
329
330    // add a viewport to the viewer and attach the scene graph.
331    viewer.setSceneData(loadedModel.get());
332
333    viewer.setCameraManipulator(new osgGA::TrackballManipulator());
334
335    viewer.realize();
336
337    // switch on the uniforms that track the modelview and projection matrices
338    osgViewer::Viewer::Windows windows;
339    viewer.getWindows(windows);
340    for(osgViewer::Viewer::Windows::iterator itr = windows.begin();
341        itr != windows.end();
342        ++itr)
343    {
344        (*itr)->getState()->setUseModelViewAndProjectionUniforms(true);
345    }
346
347    return viewer.run();
348}
Note: See TracBrowser for help on using the browser.