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 }