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

Revision 10642, 14.1 kB (checked in by robert, 5 years ago)

Ported osg::Geometry across to supporting the aliasing of vertex, color and normal etc. calls to Vertex Attributes.

Added support for automatic aliasing of vertex, normal, color etc. arrays to Vertex Attribute equivelants.

Added new osg::GLBeginEndAdapter class for runtime conversion from glBegin/glEnd codes to vertex arrray equivelants.

Added automatic shader source conversion from gl_ to osg_ builtins.

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