📄 readerwriterobj.cpp
字号:
// -*-c++-*-/* * Wavefront OBJ loader for Open Scene Graph * * Copyright (C) 2001,2007 Ulrich Hertlein <u.hertlein@sandbox.de> * * Modified by Robert Osfield to support per Drawable coord, normal and * texture coord arrays, bug fixes, and support for texture mapping. * * Writing support added 2007 by Stephan Huber, http://digitalmind.de, * some ideas taken from the dae-plugin * * The Open Scene Graph (OSG) is a cross platform C++/OpenGL library for * real-time rendering of large 3D photo-realistic models. * The OSG homepage is http://www.openscenegraph.org/ */#if defined(_MSC_VER) #pragma warning( disable : 4786 )#endif#include <string>#include <osg/Notify>#include <osg/Node>#include <osg/MatrixTransform>#include <osg/Geode>#include <osg/Geometry>#include <osg/StateSet>#include <osg/Material>#include <osg/Texture2D>#include <osg/TexGen>#include <osg/TexMat>#include <osgDB/Registry>#include <osgDB/ReadFile>#include <osgDB/FileUtils>#include <osgDB/FileNameUtils>#include <osgDB/fstream>#include <osgUtil/TriStripVisitor>#include <osgUtil/SmoothingVisitor>#include <osgUtil/Tessellator>#include "obj.h"#include "OBJWriterNodeVisitor.h"#include <map>#include <set>class ReaderWriterOBJ : public osgDB::ReaderWriter{public: ReaderWriterOBJ():_fixBlackMaterials(true) { supportsExtension("obj","Alias Wavefront OBJ format"); supportsOption("noRotation","Do not do the default rotate about X axis"); supportsOption("noTesselateLargePolygons","Do not do the default tesselation of large polygons"); supportsOption("noTriStripPolygons","Do not do the default tri stripping of polygons"); } virtual const char* className() const { return "Wavefront OBJ Reader"; } virtual ReadResult readNode(const std::string& fileName, const osgDB::ReaderWriter::Options* options) const; virtual ReadResult readNode(std::istream& fin, const Options* options) const; virtual WriteResult writeObject(const osg::Object& obj,const std::string& fileName,const Options* options=NULL) const { const osg::Node* node = dynamic_cast<const osg::Node*>(&obj); if (node) return writeNode(*node, fileName, options); else return WriteResult(WriteResult::FILE_NOT_HANDLED); } virtual WriteResult writeNode(const osg::Node& node,const std::string& fileName,const Options* options =NULL) const { if (!acceptsExtension(osgDB::getFileExtension(fileName))) return WriteResult(WriteResult::FILE_NOT_HANDLED); osgDB::ofstream f(fileName.c_str()); std::string materialFile = osgDB::getNameLessExtension(fileName) + ".mtl"; OBJWriterNodeVisitor nv(f, osgDB::getSimpleFileName(materialFile)); // we must cast away constness (const_cast<osg::Node*>(&node))->accept(nv); osgDB::ofstream mf(materialFile.c_str()); nv.writeMaterials(mf); return WriteResult(WriteResult::FILE_SAVED); } virtual WriteResult writeObject(const osg::Object& obj,std::ostream& fout,const Options* options=NULL) const { const osg::Node* node = dynamic_cast<const osg::Node*>(&obj); if (node) return writeNode(*node, fout, options); else return WriteResult(WriteResult::FILE_NOT_HANDLED); } virtual WriteResult writeNode(const osg::Node& node,std::ostream& fout,const Options* =NULL) const { // writing to a stream does not support materials OBJWriterNodeVisitor nv(fout); // we must cast away constness (const_cast<osg::Node*>(&node))->accept(nv); return WriteResult(WriteResult::FILE_SAVED); }protected: typedef std::map< std::string, osg::ref_ptr<osg::StateSet> > MaterialToStateSetMap; void buildMaterialToStateSetMap(obj::Model& model, MaterialToStateSetMap& materialToSetSetMap) const; osg::Geometry* convertElementListToGeometry(obj::Model& model, obj::Model::ElementList& elementList, bool& rotate) const; osg::Node* convertModelToSceneGraph(obj::Model& model, bool& rotate, bool& noTesselateLargePolygons, bool& noTriStripPolygons) const; inline osg::Vec3 transformVertex(const osg::Vec3& vec, const bool rotate) const ; inline osg::Vec3 transformNormal(const osg::Vec3& vec, const bool rotate) const ; bool _fixBlackMaterials;};inline osg::Vec3 ReaderWriterOBJ::transformVertex(const osg::Vec3& vec, const bool rotate) const{ if(rotate==true) { return osg::Vec3(vec.x(),-vec.z(),vec.y()); } else { return vec; }}inline osg::Vec3 ReaderWriterOBJ::transformNormal(const osg::Vec3& vec, const bool rotate) const{ if(rotate==true) { return osg::Vec3(vec.x(),-vec.z(),vec.y()); } else { return vec; }}// register with Registry to instantiate the above reader/writer.REGISTER_OSGPLUGIN(obj, ReaderWriterOBJ)static void load_material_texture( obj::Model &model, obj::Material &material, osg::StateSet *stateset, const std::string & filename, const unsigned int texture_unit ){ if (!filename.empty()) { osg::ref_ptr< osg::Image > image; if ( !model.getDatabasePath().empty() ) { // first try with database path of parent. image = osgDB::readImageFile(model.getDatabasePath()+'/'+filename); } if ( !image.valid() ) { // if not already set then try the filename as is. image = osgDB::readImageFile(filename); } if ( image.valid() ) { osg::Texture2D* texture = new osg::Texture2D( image.get() ); osg::Texture::WrapMode textureWrapMode = osg::Texture::REPEAT; texture->setWrap(osg::Texture2D::WRAP_R, textureWrapMode); texture->setWrap(osg::Texture2D::WRAP_S, textureWrapMode); texture->setWrap(osg::Texture2D::WRAP_T, textureWrapMode); stateset->setTextureAttributeAndModes( texture_unit, texture,osg::StateAttribute::ON ); if ( material.textureReflection ) { osg::TexGen* texgen = new osg::TexGen; texgen->setMode(osg::TexGen::SPHERE_MAP); stateset->setTextureAttributeAndModes( texture_unit,texgen,osg::StateAttribute::ON ); } if ( image->isImageTranslucent()) { osg::notify(osg::INFO)<<"Found transparent image"<<std::endl; stateset->setMode(GL_BLEND, osg::StateAttribute::ON); stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); } } } if (material.uScale != 1.0f || material.vScale != 1.0f || material.uOffset != 0.0f || material.vOffset != 0.0f) { osg::Matrix mat; if (material.uScale != 1.0f || material.vScale != 1.0f) { osg::notify(osg::DEBUG_INFO) << "Obj TexMat scale=" << material.uScale << "," << material.vScale << std::endl; mat *= osg::Matrix::scale(material.uScale, material.vScale, 1.0); } if (material.uOffset != 0.0f || material.vOffset != 0.0f) { osg::notify(osg::DEBUG_INFO) << "Obj TexMat offset=" << material.uOffset << "," << material.uOffset << std::endl; mat *= osg::Matrix::translate(material.uOffset, material.vOffset, 0.0); } osg::TexMat* texmat = new osg::TexMat; texmat->setMatrix(mat); stateset->setTextureAttributeAndModes( texture_unit,texmat,osg::StateAttribute::ON ); }}void ReaderWriterOBJ::buildMaterialToStateSetMap(obj::Model& model, MaterialToStateSetMap& materialToStateSetMap) const{ if (_fixBlackMaterials) { // hack to fix Maya exported models that contian all black materials. int numBlack = 0; int numNotBlack = 0; obj::Model::MaterialMap::iterator itr; for(itr = model.materialMap.begin(); itr != model.materialMap.end(); ++itr) { obj::Material& material = itr->second; if (material.ambient==osg::Vec4(0.0f,0.0f,0.0f,1.0f) && material.diffuse==osg::Vec4(0.0f,0.0f,0.0f,1.0f)) { ++numBlack; } else { ++numNotBlack; } } if (numNotBlack==0 && numBlack!=0) { for(itr = model.materialMap.begin(); itr != model.materialMap.end(); ++itr) { obj::Material& material = itr->second; if (material.ambient==osg::Vec4(0.0f,0.0f,0.0f,1.0f) && material.diffuse==osg::Vec4(0.0f,0.0f,0.0f,1.0f)) { material.ambient.set(0.3f,0.3f,0.3f,1.0f); material.diffuse.set(1.0f,1.0f,1.0f,1.0f); } } } } for(obj::Model::MaterialMap::iterator itr = model.materialMap.begin(); itr != model.materialMap.end(); ++itr) { obj::Material& material = itr->second; osg::ref_ptr< osg::StateSet > stateset = new osg::StateSet; bool isTransparent = false; // handle material colors // http://java3d.j3d.org/utilities/loaders/obj/sun.html if (material.illum != 0) { osg::Material* osg_material = new osg::Material; stateset->setAttribute(osg_material); osg_material->setAmbient(osg::Material::FRONT_AND_BACK,material.ambient); osg_material->setDiffuse(osg::Material::FRONT_AND_BACK,material.diffuse); osg_material->setEmission(osg::Material::FRONT_AND_BACK,material.emissive); if (material.illum == 2) { osg_material->setSpecular(osg::Material::FRONT_AND_BACK,material.specular); } else { osg_material->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4(0,0,0,1)); } osg_material->setShininess(osg::Material::FRONT_AND_BACK,(material.Ns/1000.0f)*128.0f ); // note OBJ shiniess is 0..1000. if (material.ambient[3]!=1.0 || material.diffuse[3]!=1.0 || material.specular[3]!=1.0|| material.emissive[3]!=1.0) { osg::notify(osg::INFO)<<"Found transparent material"<<std::endl; isTransparent = true; } } // handle textures enum TextureUnit { TEXTURE_UNIT_KD = 0, TEXTURE_UNIT_OPACITY }; load_material_texture( model, material, stateset.get(), material.map_Kd, TEXTURE_UNIT_KD ); load_material_texture( model, material, stateset.get(), material.map_opacity, TEXTURE_UNIT_OPACITY ); if (isTransparent) { stateset->setMode(GL_BLEND, osg::StateAttribute::ON); stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); } materialToStateSetMap[material.name] = stateset.get(); }}osg::Geometry* ReaderWriterOBJ::convertElementListToGeometry(obj::Model& model, obj::Model::ElementList& elementList, bool& rotate) const{ unsigned int numVertexIndices = 0; unsigned int numNormalIndices = 0; unsigned int numTexCoordIndices = 0; unsigned int numPointElements = 0; unsigned int numPolylineElements = 0; unsigned int numPolygonElements = 0; obj::Model::ElementList::iterator itr; for(itr=elementList.begin(); itr!=elementList.end(); ++itr) { obj::Element& element = *(*itr); numVertexIndices += element.vertexIndices.size(); numNormalIndices += element.normalIndices.size(); numTexCoordIndices += element.texCoordIndices.size(); numPointElements += (element.dataType==obj::Element::POINTS) ? 1 : 0; numPolylineElements += (element.dataType==obj::Element::POLYLINE) ? 1 : 0; numPolygonElements += (element.dataType==obj::Element::POLYGON) ? 1 : 0; } if (numVertexIndices==0) return 0; if (numNormalIndices!=0 && numNormalIndices!=numVertexIndices) { osg::notify(osg::NOTICE)<<"Incorrect number of normals, ignore them"<<std::endl; numNormalIndices = 0; } if (numTexCoordIndices!=0 && numTexCoordIndices!=numVertexIndices) { osg::notify(osg::NOTICE)<<"Incorrect number of normals, ignore them"<<std::endl; numTexCoordIndices = 0; } osg::Vec3Array* vertices = numVertexIndices ? new osg::Vec3Array : 0; osg::Vec3Array* normals = numNormalIndices ? new osg::Vec3Array : 0; osg::Vec2Array* texcoords = numTexCoordIndices ? new osg::Vec2Array : 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -