Hair export to Mitsuba

Philemo_CarraraPhilemo_Carrara Posts: 1,175
edited November 2015 in Carrara SDK Developer Discussion

Following a request from PhilW and for those who are interested, this is how I handled the hair export from Carrara to Mitsuba :
In Carrara, the Hair primitive exports segments as renderable for preview in the assembly room. The shaping done in the shader (frizz and so one) are kept.

Exporting from Carrara

ptree CarraraSceneParser::createHair(I3DShInstance * instance){ ptree result; TMCCountedPtr shObject; instance->Get3DObject(&shObject;); const TRenderableAndTfmArray * renderables; instance->GetTreeElement()->BeginGetRenderables(renderables,false); instance->GetTreeElement()->EndGetRenderables(); std::vector segments; std::vector points; for (uint32 i = 0; i < renderables->GetElemCount(); i++){  TRenderableAndTfm rf;  renderables->GetElem(i,rf);  I3DShRenderable::EType t =  rf.fRenderable->GetGeometryType();  if (t == I3DShRenderable::EType::kType_Segment) {   const TSegmentMesh * segment = rf.fRenderable->GetSegmentMesh();   for (uint32 j = 0; j < segment->fVertex.GetElemCount(); j++) {    TVector3 vec = segment->fVertex[j];    points.push_back (MinVec3(vec.x,vec.y,vec.z));   }   for (uint32 j = 0; j < segment->fSegmentIndices.GetElemCount(); j++) {    TIndex2 extr = segment->fSegmentIndices[j];    segments.push_back(MinVec2I(extr.x,extr.y));   }  } } TMCDynamicString name; shObject->GetName(name); std::string meshName = name.StrGet(); meshName = "M-" + meshName; std::string filename; if (masters.find(meshName) == masters.end()) {  TR("serializing %s %s",path.c_str(),meshName.c_str());  MultiThreadEndJobNotifier * notifier = multiThreadManager->createNotifier();  multiThreadManager->acquire();  filename = GlueUtils::getInstance()->serializeHair(path,meshName,points,segments,notifier);

 

Mitsuba hair file format is quite simple: from the documentation

There is also a binary format, which starts with the identifier “BINARY_HAIR” (11 bytes), followedby the number of vertices as a 32-bit little endian integer. The remainder of the file consists of thevertex positions stored as single-precision XYZ coordinates (again in little-endian byte ordering). Tomark the beginning of a new hair strand, a single +8 floating point value can be inserted betweenthe vertex data.


Serializing for Mitsuba

 

void HairSerializer::run() { boost::filesystem::path pa = boost::filesystem::path(path); pa /= boost::filesystem::path(name); ref fs = new FileStream(pa,mitsuba::FileStream::ETruncWrite); fs->setByteOrder(mitsuba::FileStream::ELittleEndian); int nbHairs = 0; int prev = -1; for (int i = 0; i < segments.size(); i++) {  if (segments[ i ].x != prev)    nbHairs++;  prev = segments[ i ].y; } const char *binaryHeader = "BINARY_HAIR"; fs->write(binaryHeader,11); fs->writeUInt(((int)segments.size())+nbHairs); bool notFirst = false; prev = -1; for (int i = 0; i < segments.size(); i++) {  if (segments[ i ].x != prev) {   if (notFirst) {    fs->writeFloat(std::numeric_limits::infinity());   }   fs->writeFloat(points[segments[ i ].x].x);   fs->writeFloat(points[segments[ i ].x].y);   fs->writeFloat(points[segments[ i ].x].z);  }  fs->writeFloat(points[segments[ i ].y].x);  fs->writeFloat(points[segments[ i ].y].y);  fs->writeFloat(points[segments[ i ].y].z);  prev = segments[ i ].y;  notFirst = true; } fs->close(); notified->ended();}

 

 

Post edited by Richard Haseltine on
Sign In or Register to comment.