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