Hair export to Mitsuba
Philemo_Carrara
Posts: 1,175
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
Comments
Mitsuba 2 is out now
look here (when interested):
> https://github.com/mitsuba-renderer/mitsuba2
> https://mitsuba2.readthedocs.io/en/latest/src/getting_started/intro.html