00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00027 #include <iostream>
00028 #include <iomanip>
00029 #include <sstream>
00030 #include <cctype>
00031 #include "ShObjMesh.hpp"
00032
00033
00034
00035 namespace ShUtil {
00036
00037 struct Triple {
00038 int idx[3];
00039
00040
00041
00042
00043 Triple(std::istream &in) {
00044 idx[0] = idx[1] = idx[2] = 0;
00045 while(in.peek() != '\n' && isspace(in.peek())) in.ignore();
00046
00047
00048 in >> std::noskipws;
00049 for(int i = 0; i < 3;) {
00050 in >> idx[i];
00051 if( !in ) {
00052 in.clear();
00053 if(in.peek() == '/') {
00054 ++i;
00055 in.ignore();
00056 }else {
00057 return;
00058 }
00059 }
00060 }
00061 in >> std::skipws;
00062 }
00063
00064 int operator[](int i) { return idx[i]; }
00065 };
00066
00067 typedef std::vector<Triple> ShObjIndexedFace;
00068
00069 ShObjVertex::ShObjVertex(const ShPoint3f &p)
00070 : pos(p) {}
00071
00072 ShObjMesh::ShObjMesh() {
00073 }
00074
00075 ShObjMesh::ShObjMesh(std::istream &in) {
00076 readObj(in);
00077 }
00078
00079 std::istream& ShObjMesh::readObj(std::istream &in) {
00080 char ch = 0;
00081 typedef std::vector<Vertex*> VertexVec;
00082 typedef std::vector<ShTexCoord2f> TexCoordVec;
00083 typedef std::vector<ShNormal3f> NormalVec;
00084 typedef std::vector<ShVector3f> TangentVec;
00085 typedef std::vector<ShObjIndexedFace> FaceVec;
00086
00087 VertexVec vertexVec;
00088 TexCoordVec tcVec;
00089 NormalVec normVec;
00090 TangentVec tangentVec;
00091 FaceVec faceVec;
00092
00093
00094 clear();
00095
00096
00097 while (in) {
00098 in >> std::ws >> ch;
00099 if (!in) break;
00100 switch (ch) {
00101 case 'v': {
00102 ch = in.get();
00103 switch (ch) {
00104 case ' ': {
00105 float x, y, z;
00106 in >> x >> y >> z;
00107 vertexVec.push_back(new Vertex(ShPoint3f(x, y, z)));
00108 break;
00109 }
00110 case 't': {
00111 float u, v;
00112 in >> u >> v;
00113 tcVec.push_back(ShTexCoord2f(u, v));
00114 break;
00115 }
00116 case 'n': {
00117
00118 float x, y, z;
00119 in >> x >> y >> z;
00120 normVec.push_back(ShNormal3f(x, y, z));
00121 break;
00122 }
00123 }
00124 break;
00125 }
00126 case 'r': {
00127 float x, y, z;
00128 in >> x >> y >> z;
00129 tangentVec.push_back(ShVector3f(x, y, z));
00130 break;
00131 }
00132 case 'f': {
00133 ShObjIndexedFace f;
00134 for(;;) {
00135 Triple triple(in);
00136 if( triple[0] == 0 ) break;
00137 f.push_back(triple);
00138 }
00139 faceVec.push_back(f);
00140 break;
00141 }
00142 case '#':
00143 case '$':
00144 case 'l':
00145 case 'p':
00146 case 'm':
00147 case 'g':
00148 case 's':
00149 case 'u':
00150 default:
00151 break;
00152 }
00153 while (in && in.get() != '\n') ;
00154 }
00155
00156
00157 for(std::size_t i = 0; i < faceVec.size(); ++i) {
00158 VertexList vl;
00159 for(ShObjIndexedFace::iterator I = faceVec[i].begin(); I != faceVec[i].end(); ++I) {
00160 int vi = (*I)[0] - 1;
00161 if( vi == -1 || vi >= (int)vertexVec.size() ) {
00162 std::ostringstream os;
00163 os << "Invalid vertex index " << vi << " in OBJ file.";
00164 shError( ShException(os.str()));
00165 }
00166 vl.push_back(vertexVec[vi]);
00167 }
00168 Face* face = addFace(vl);
00169
00170
00171 Edge* edge = face->edge;
00172 for(ShObjIndexedFace::iterator I = faceVec[i].begin(); I != faceVec[i].end(); ++I, edge = edge->next) {
00173 int tci = (*I)[1] - 1;
00174 int ni = (*I)[2] - 1;
00175
00176 if( tci != -1 ) {
00177 if( tci >= (int)tcVec.size() ) {
00178 std::ostringstream os;
00179 os << "Invalid texcoord index " << tci << " in OBJ file.";
00180 shError( ShException(os.str()));
00181 }
00182 edge->texcoord = tcVec[tci];
00183 } else edge->texcoord *= 0.0f;
00184
00185 if( ni != -1 ) {
00186 if( ni >= (int)normVec.size() ) {
00187 std::ostringstream os;
00188 os << "Invalid normal index " << ni << " in OBJ file.";
00189 shError( ShException(os.str()));
00190 }
00191 edge->normal = normVec[ni];
00192
00193 if( ni >= (int)tangentVec.size() ) {
00194 edge->tangent *= 0.0f;
00195 } else {
00196 edge->tangent = tangentVec[ni];
00197 }
00198 }
00199 }
00200 }
00201
00202 earTriangulate();
00203 generateFaceNormals();
00204
00205 int badNorms = generateVertexNormals();
00206 if(badNorms > 0) SH_DEBUG_WARN("OBJ file has " << badNorms << " vertices without normals");
00207
00208 int badTangents = generateTangents();
00209 if(badTangents > 0) SH_DEBUG_WARN("OBJ file has " << badTangents << " vertices without tangents");
00210
00211 int badTexCoords = generateSphericalTexCoords();
00212 if(badTexCoords > 0) SH_DEBUG_WARN("OBJ file has " << badTexCoords << " vertices without texture coordinates.");
00213
00214
00215 return in;
00216 }
00217
00218 void ShObjMesh::generateFaceNormals() {
00219 for(FaceSet::iterator I = faces.begin(); I != faces.end(); ++I) {
00220 Face& face = **I;
00221 Edge& e01 = *(face.edge);
00222 Edge& e02 = *(e01.next);
00223 ShVector3f v01 = e01.end->pos - e01.start->pos;
00224 ShVector3f v02 = e02.end->pos - e02.start->pos;
00225 face.normal = cross(v01, v02);
00226 }
00227 }
00228
00229 int ShObjMesh::generateVertexNormals(bool force) {
00230 typedef std::map<Vertex*, ShPoint3f> NormalSumMap;
00231 typedef std::map<Vertex*, int> NormalSumCount;
00232 NormalSumMap nsm;
00233 NormalSumCount nscount;
00234 for(EdgeSet::iterator I = edges.begin(); I != edges.end(); ++I) {
00235 Edge &e = **I;
00236 if( force || dot(e.normal, e.normal).getValue(0) == 0 ) {
00237 nsm[e.start] = ShConstAttrib3f(0.0f, 0.0f, 0.0f);
00238 nscount[e.start] = 0;
00239 }
00240 }
00241 if( nsm.empty() ) return 0;
00242
00243 for(EdgeSet::iterator I = edges.begin(); I != edges.end(); ++I) {
00244 Vertex *v = (*I)->start;
00245 if( nsm.count(v) > 0 ) {
00246 nsm[v] += (*I)->face->normal;
00247 nscount[v]++;
00248 }
00249 }
00250
00251 for(EdgeSet::iterator I = edges.begin(); I != edges.end(); ++I) {
00252 Vertex *v = (*I)->start;
00253 if( nsm.count(v) > 0 ) {
00254 (*I)->normal = nsm[v] / (float)nscount[v];
00255 }
00256 }
00257 return nsm.size();
00258 }
00259
00260 int ShObjMesh::generateTangents(bool force) {
00261 int changed = 0;
00262 for(EdgeSet::iterator I = edges.begin(); I != edges.end(); ++I) {
00263 Edge &e = **I;
00264 if( force || dot(e.tangent, e.tangent).getValue(0) == 0) {
00265 e.tangent = cross(e.normal, ShVector3f(0.0f, 1.0f, 0.0f));
00266 changed++;
00267 }
00268 }
00269 return changed;
00270 }
00271
00272 int ShObjMesh::generateSphericalTexCoords(bool force) {
00273 if( !force ) {
00274
00275 for(EdgeSet::iterator I = edges.begin(); I != edges.end(); ++I) {
00276 if( dot((*I)->texcoord, (*I)->texcoord).getValue(0) != 0) {
00277 return 0;
00278 }
00279 }
00280 }
00281
00282
00283 int changed = 0;
00284 ShPoint3f center;
00285 for(VertexSet::iterator I = verts.begin(); I != verts.end(); ++I) {
00286 center += (*I)->pos;
00287 }
00288 center *= 1.0f / verts.size();
00289
00290 for(EdgeSet::iterator I = edges.begin(); I != edges.end(); ++I) {
00291 Edge &e = **I;
00292 if( force || dot(e.texcoord, e.texcoord).getValue(0) == 0) {
00293 ShVector3f cv = normalize(e.start->pos - center);
00294 e.texcoord(0) = atan2(cv.getValue(2), cv.getValue(0));
00295 e.texcoord(1) = acos(cv.getValue(1));
00296 changed++;
00297 }
00298 }
00299 return changed;
00300 }
00301
00302 void ShObjMesh::normalizeNormals() {
00303 for(EdgeSet::iterator I = edges.begin(); I != edges.end(); ++I) {
00304 (*I)->normal = normalize((*I)->normal);
00305 }
00306
00307 for(FaceSet::iterator J = faces.begin(); J != faces.end(); ++J) {
00308 (*J)->normal = normalize((*J)->normal);
00309 }
00310 }
00311
00312 struct ObjVertLess {
00313 static const float EPS;
00314
00315 inline bool operator()( const ShObjVertex *a, const ShObjVertex *b ) const {
00316 float aval[3], bval[3];
00317 a->pos.getValues(aval); b->pos.getValues(bval);
00318
00319 return (aval[0] < bval[0] - EPS) || (
00320 (aval[0] < bval[0] + EPS) && (
00321 (aval[1] < bval[1] - EPS) || (
00322 (aval[1] < bval[1] + EPS) &&
00323 (aval[2] < bval[2] - EPS))));
00324 }
00325 };
00326
00327 const float ObjVertLess::EPS = 1e-5;
00328
00329 void ShObjMesh::consolidateVertices() {
00330 mergeVertices<ObjVertLess>();
00331 }
00332
00333
00334 std::istream& operator>>(std::istream &in, ShObjMesh &mesh) {
00335 return mesh.readObj(in);
00336 }
00337
00338 }