root/OpenSceneGraph/trunk/src/osgPlugins/obj/ReaderWriterOBJ.cpp @ 3327

Revision 3327, 15.4 kB (checked in by robert, 10 years ago)

Added handling of short (<=4 points) polygons as tri fans and the rest
as polygons which are tesselated, to improve load and build time, yet
still resselating the large polygons that need it.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1// -*-c++-*-
2
3/*
4 * Wavefront OBJ loader for Open Scene Graph
5 *
6 * Copyright (C) 2001 Ulrich Hertlein <u.hertlein@web.de>
7 *
8 * Modified by Robert Osfield to support per Drawable coord, normal and
9 * texture coord arrays, bug fixes, and support for texture mapping.
10 *
11 * The Open Scene Graph (OSG) is a cross platform C++/OpenGL library for
12 * real-time rendering of large 3D photo-realistic models.
13 * The OSG homepage is http://www.openscenegraph.org/
14 */
15
16#if defined(_MSC_VER)
17    #pragma warning( disable : 4786 )
18#endif
19
20#include <string>
21
22#include <osg/Notify>
23#include <osg/Node>
24#include <osg/MatrixTransform>
25#include <osg/Geode>
26
27#include <osg/Geometry>
28#include <osg/StateSet>
29#include <osg/Material>
30#include <osg/Texture2D>
31#include <osg/TexGen>
32#include <osg/TexMat>
33
34#include <osgDB/Registry>
35#include <osgDB/ReadFile>
36#include <osgDB/FileUtils>
37#include <osgDB/FileNameUtils>
38
39#include <osgUtil/TriStripVisitor>
40#include <osgUtil/SmoothingVisitor>
41#include <osgUtil/Tesselator>
42
43#include "obj.h"
44
45#include <map>
46#include <set>
47
48class ReaderWriterOBJ : public osgDB::ReaderWriter
49{
50public:
51    ReaderWriterOBJ() { }
52
53    virtual const char* className() { return "Wavefront OBJ Reader"; }
54    virtual bool acceptsExtension(const std::string& extension) {
55        return osgDB::equalCaseInsensitive(extension,"obj");
56    }
57
58    virtual ReadResult readNode(const std::string& fileName, const osgDB::ReaderWriter::Options*);
59
60
61
62protected:
63
64    typedef std::map< std::string, osg::ref_ptr<osg::StateSet> > MaterialToStateSetMap;
65   
66    void buildMaterialToStateSetMap(obj::Model& model, MaterialToStateSetMap& materialToSetSetMap);
67   
68    osg::Geometry* convertElementListToGeometry(obj::Model& model, obj::Model::ElementList& elementList);
69   
70    osg::Node* convertModelToSceneGraph(obj::Model& model);
71
72    inline osg::Vec3 transformVertex(const osg::Vec3& vec) { return osg::Vec3(vec.x(),-vec.z(),vec.y()); }
73    inline osg::Vec3 transformNormal(const osg::Vec3& vec) { return osg::Vec3(vec.x(),-vec.z(),vec.y()); }
74   
75};
76
77
78// register with Registry to instantiate the above reader/writer.
79osgDB::RegisterReaderWriterProxy<ReaderWriterOBJ> g_objReaderWriterProxy;
80
81void ReaderWriterOBJ::buildMaterialToStateSetMap(obj::Model& model, MaterialToStateSetMap& materialToStateSetMap)
82{
83    for(obj::Model::MaterialMap::iterator itr = model.materialMap.begin();
84        itr != model.materialMap.end();
85        ++itr)
86    {
87        obj::Material& material = itr->second;
88       
89        osg::StateSet* stateset = new osg::StateSet;
90
91        // handle material colors
92        {
93            osg::Material* osg_material = new osg::Material;
94            stateset->setAttribute(osg_material);
95
96            osg_material->setAmbient(osg::Material::FRONT_AND_BACK,material.ambient);
97            osg_material->setDiffuse(osg::Material::FRONT_AND_BACK,material.diffuse);
98            osg_material->setSpecular(osg::Material::FRONT_AND_BACK,material.specular);
99            osg_material->setShininess(osg::Material::FRONT_AND_BACK,(material.shininess/1000.0f)*128.0f ); // note OBJ shiniess is 0..1000.
100        }
101       
102        // handle textures
103        if (!material.map_Kd.empty())
104        {
105            std::string filename = material.map_Kd;
106            osg::Image* image = osgDB::readImageFile(filename);
107            if (image)
108            {
109                osg::Texture2D* texture = new osg::Texture2D(image);
110                stateset->setTextureAttributeAndModes(0,texture,osg::StateAttribute::ON);
111            }
112        }
113
114       
115        materialToStateSetMap[material.name] = stateset;
116       
117    }
118}
119
120osg::Geometry* ReaderWriterOBJ::convertElementListToGeometry(obj::Model& model, obj::Model::ElementList& elementList)
121{
122   
123    unsigned int numVertexIndices = 0;
124    unsigned int numNormalIndices = 0;
125    unsigned int numTexCoordIndices = 0;
126   
127    unsigned int numPointElements = 0;
128    unsigned int numPolylineElements = 0;
129    unsigned int numPolygonElements = 0;
130
131    obj::Model::ElementList::iterator itr;
132    for(itr=elementList.begin();
133        itr!=elementList.end();
134        ++itr)
135    {
136        obj::Element& element = *(*itr);
137
138        numVertexIndices += element.vertexIndices.size();
139        numNormalIndices += element.normalIndices.size();
140        numTexCoordIndices += element.texCoordIndices.size();
141
142        numPointElements += (element.dataType==obj::Element::POINTS) ? 1 : 0;
143        numPolylineElements += (element.dataType==obj::Element::POLYLINE) ? 1 : 0;
144        numPolygonElements += (element.dataType==obj::Element::POLYGON) ? 1 : 0;
145
146    }
147
148    if (numVertexIndices==0) return 0;
149   
150    if (numNormalIndices!=0 && numNormalIndices!=numVertexIndices)
151    {
152        osg::notify(osg::NOTICE)<<"Incorrect number of normals, ignore them"<<std::endl;
153        numNormalIndices = 0;
154    }
155   
156    if (numTexCoordIndices!=0 && numTexCoordIndices!=numVertexIndices)
157    {
158        osg::notify(osg::NOTICE)<<"Incorrect number of normals, ignore them"<<std::endl;
159        numTexCoordIndices = 0;
160    }
161   
162    osg::Vec3Array* vertices = numVertexIndices ? new osg::Vec3Array : 0;
163    osg::Vec3Array* normals = numNormalIndices ? new osg::Vec3Array : 0;
164    osg::Vec2Array* texcoords = numTexCoordIndices ? new osg::Vec2Array : 0;
165   
166    if (vertices) vertices->reserve(numVertexIndices);
167    if (normals) normals->reserve(numNormalIndices);
168    if (texcoords) texcoords->reserve(numTexCoordIndices);
169   
170    osg::Geometry* geometry = new osg::Geometry;
171    if (vertices) geometry->setVertexArray(vertices);
172    if (normals)
173    {
174        geometry->setNormalArray(normals);
175        geometry->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
176    }
177    if (texcoords)
178    {
179        geometry->setTexCoordArray(0,texcoords);
180    }
181   
182
183    if (numPointElements>0)
184    {
185        unsigned int startPos = vertices->size();
186        unsigned int numPoints = 0;
187        for(itr=elementList.begin();
188            itr!=elementList.end();
189            ++itr)
190        {
191            obj::Element& element = *(*itr);
192            if (element.dataType==obj::Element::POINTS)
193            {
194                for(obj::Element::IndexList::iterator index_itr = element.vertexIndices.begin();
195                    index_itr != element.vertexIndices.end();
196                    ++index_itr)
197                {
198                    vertices->push_back(transformVertex(model.vertices[*index_itr]));
199                    ++numPoints;
200                }
201                if (numNormalIndices)
202                {
203                    for(obj::Element::IndexList::iterator index_itr = element.normalIndices.begin();
204                        index_itr != element.normalIndices.end();
205                        ++index_itr)
206                    {
207                        normals->push_back(transformNormal(model.normals[*index_itr]));
208                    }
209                }
210                if (numTexCoordIndices)
211                {
212                    for(obj::Element::IndexList::iterator index_itr = element.texCoordIndices.begin();
213                        index_itr != element.texCoordIndices.end();
214                        ++index_itr)
215                    {
216                        texcoords->push_back(model.texcoords[*index_itr]);
217                    }
218                }
219            }
220        }
221
222        osg::DrawArrays* drawArrays = new osg::DrawArrays(GL_POINTS,startPos,numPoints);
223        geometry->addPrimitiveSet(drawArrays);
224    }
225   
226    if (numPolylineElements>0)
227    {
228        unsigned int startPos = vertices->size();
229        osg::DrawArrayLengths* drawArrayLengths = new osg::DrawArrayLengths(GL_LINES,startPos);
230
231        for(itr=elementList.begin();
232            itr!=elementList.end();
233            ++itr)
234        {
235            obj::Element& element = *(*itr);
236            if (element.dataType==obj::Element::POLYLINE)
237            {
238                drawArrayLengths->push_back(element.vertexIndices.size());
239
240                for(obj::Element::IndexList::iterator index_itr = element.vertexIndices.begin();
241                    index_itr != element.vertexIndices.end();
242                    ++index_itr)
243                {
244                    vertices->push_back(transformVertex(model.vertices[*index_itr]));
245                }
246                if (numNormalIndices)
247                {
248                    for(obj::Element::IndexList::iterator index_itr = element.normalIndices.begin();
249                        index_itr != element.normalIndices.end();
250                        ++index_itr)
251                    {
252                        normals->push_back(transformNormal(model.normals[*index_itr]));
253                    }
254                }
255                if (numTexCoordIndices)
256                {
257                    for(obj::Element::IndexList::iterator index_itr = element.texCoordIndices.begin();
258                        index_itr != element.texCoordIndices.end();
259                        ++index_itr)
260                    {
261                        texcoords->push_back(model.texcoords[*index_itr]);
262                    }
263                }
264            }
265        }
266
267        geometry->addPrimitiveSet(drawArrayLengths);
268
269    }
270
271    // #define USE_DRAWARRAYLENGTHS
272
273    if (numPolygonElements>0)
274    {
275        unsigned int startPos = vertices->size();
276       
277        #ifdef USE_DRAWARRAYLENGTHS
278            osg::DrawArrayLengths* drawArrayLengths = new osg::DrawArrayLengths(GL_POLYGON,startPos);
279            geometry->addPrimitiveSet(drawArrayLengths);
280        #endif
281
282        for(itr=elementList.begin();
283            itr!=elementList.end();
284            ++itr)
285        {
286            obj::Element& element = *(*itr);
287            if (element.dataType==obj::Element::POLYGON)
288            {
289
290                #ifdef USE_DRAWARRAYLENGTHS
291                    drawArrayLengths->push_back(element.vertexIndices.size());
292                #else
293                    if (element.vertexIndices.size()>4)
294                    {
295                        osg::DrawArrays* drawArrays = new osg::DrawArrays(GL_POLYGON,startPos,element.vertexIndices.size());
296                        startPos += element.vertexIndices.size();
297                        geometry->addPrimitiveSet(drawArrays);
298                    }
299                    else
300                    {
301                        osg::DrawArrays* drawArrays = new osg::DrawArrays(GL_TRIANGLE_FAN,startPos,element.vertexIndices.size());
302                        startPos += element.vertexIndices.size();
303                        geometry->addPrimitiveSet(drawArrays);
304                    }
305                #endif
306
307           
308                if (model.needReverse(element))
309                {
310                    // need to reverse so add to OSG arrays in same order as in OBJ, as OSG assume anticlockwise ordering.
311                    for(obj::Element::IndexList::reverse_iterator index_itr = element.vertexIndices.rbegin();
312                        index_itr != element.vertexIndices.rend();
313                        ++index_itr)
314                    {
315                        vertices->push_back(transformVertex(model.vertices[*index_itr]));
316                    }
317                    if (numNormalIndices)
318                    {
319                        for(obj::Element::IndexList::reverse_iterator index_itr = element.normalIndices.rbegin();
320                            index_itr != element.normalIndices.rend();
321                            ++index_itr)
322                        {
323                            normals->push_back(transformNormal(model.normals[*index_itr]));
324                        }
325                    }
326                    if (numTexCoordIndices)
327                    {
328                        for(obj::Element::IndexList::reverse_iterator index_itr = element.texCoordIndices.rbegin();
329                            index_itr != element.texCoordIndices.rend();
330                            ++index_itr)
331                        {
332                            texcoords->push_back(model.texcoords[*index_itr]);
333                        }
334                    }
335                }
336                else
337                {
338                    // no need to reverse so add to OSG arrays in same order as in OBJ.
339                    for(obj::Element::IndexList::iterator index_itr = element.vertexIndices.begin();
340                        index_itr != element.vertexIndices.end();
341                        ++index_itr)
342                    {
343                        vertices->push_back(transformVertex(model.vertices[*index_itr]));
344                    }
345                    if (numNormalIndices)
346                    {
347                        for(obj::Element::IndexList::iterator index_itr = element.normalIndices.begin();
348                            index_itr != element.normalIndices.end();
349                            ++index_itr)
350                        {
351                            normals->push_back(transformNormal(model.normals[*index_itr]));
352                        }
353                    }
354                    if (numTexCoordIndices)
355                    {
356                        for(obj::Element::IndexList::iterator index_itr = element.texCoordIndices.begin();
357                            index_itr != element.texCoordIndices.end();
358                            ++index_itr)
359                        {
360                            texcoords->push_back(model.texcoords[*index_itr]);
361                        }
362                    }
363                }
364            }
365        }
366
367
368    }
369   
370    return geometry;
371}
372
373osg::Node* ReaderWriterOBJ::convertModelToSceneGraph(obj::Model& model)
374{
375
376    if (model.elementStateMap.empty()) return 0;
377
378    osg::Group* group = new osg::Group;
379
380    // set up the materials
381    MaterialToStateSetMap materialToSetSetMap;
382    buildMaterialToStateSetMap(model, materialToSetSetMap);
383
384    // go through the groups of related elements and build geometry from them.
385    for(obj::Model::ElementStateMap::iterator itr=model.elementStateMap.begin();
386        itr!=model.elementStateMap.end();
387        ++itr)
388    {
389   
390        const obj::ElementState& es = itr->first;
391        obj::Model::ElementList& el = itr->second;
392
393        osg::Geometry* geometry = convertElementListToGeometry(model,el);
394
395        if (geometry)
396        {
397
398            osg::StateSet* stateset = materialToSetSetMap[es.materialName].get();
399            geometry->setStateSet(stateset);
400       
401            // tesseleate any large polygons
402            osgUtil::Tesselator tesselator;
403            tesselator.retesselatePolygons(*geometry);
404
405            // tri strip polygons to improve graphics peformance
406            osgUtil::TriStripVisitor tsv;
407            tsv.stripify(*geometry);
408
409            // if no normals present add them.
410            if (!geometry->getNormalArray() || geometry->getNormalArray()->getNumElements()==0)
411            {
412                osgUtil::SmoothingVisitor tsv;
413                tsv.smooth(*geometry);
414            }
415
416            osg::Geode* geode = new osg::Geode;
417            geode->addDrawable(geometry);
418            geode->setName(es.objectName);
419
420            group->addChild(geode);
421
422        }
423    }
424
425    return group;
426}
427
428
429// read file and convert to OSG.
430osgDB::ReaderWriter::ReadResult ReaderWriterOBJ::readNode(const std::string& file, const osgDB::ReaderWriter::Options*)
431{
432    std::string ext = osgDB::getLowerCaseFileExtension(file);
433    if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;
434
435    std::string fileName = osgDB::findDataFile( file );
436    if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;
437   
438   
439    std::ifstream fin(fileName.c_str());
440    if (fin)
441    {
442        obj::Model model;
443        model.readOBJ(fin);
444       
445        osg::Node* node = convertModelToSceneGraph(model);
446        return node;
447    }
448   
449    return ReadResult::FILE_NOT_HANDLED;
450}
Note: See TracBrowser for help on using the browser.