diff --git a/README.md b/README.md index 35c04c2..140f67b 100644 --- a/README.md +++ b/README.md @@ -35,11 +35,19 @@ A few screenshots: - Ingo Wald - Fabio Pellacini (University of Rome) - Stefan Zellman (University of Cologne) +- Will Usher +- Nate Morrical - lots of other people, through suggestions, bug reports, etc ... # Release Notes +V 2.3: + +- added 'hair' material (can now parse pbrt v3 hair files) +- removed all DLL build for windows; now using only static libraries on windows + (this avoids windows issues with passing std::string etc through dll boundaries) + V 2.2: - have first area light sources (distant and infinite) diff --git a/pbrtParser/impl/semantic/BinaryFileFormat.cpp b/pbrtParser/impl/semantic/BinaryFileFormat.cpp index a3edf8a..b4258fe 100644 --- a/pbrtParser/impl/semantic/BinaryFileFormat.cpp +++ b/pbrtParser/impl/semantic/BinaryFileFormat.cpp @@ -67,6 +67,7 @@ namespace pbrt { TYPE_METAL_MATERIAL, TYPE_PLASTIC_MATERIAL, TYPE_TRANSLUCENT_MATERIAL, + TYPE_HAIR_MATERIAL, TYPE_TEXTURE=30, TYPE_IMAGE_TEXTURE, @@ -299,6 +300,8 @@ namespace pbrt { return std::make_shared(); case TYPE_METAL_MATERIAL: return std::make_shared(); + case TYPE_HAIR_MATERIAL: + return std::make_shared(); case TYPE_FILM: return std::make_shared(vec2i(0)); case TYPE_CAMERA: @@ -1379,6 +1382,26 @@ namespace pbrt { } + /*! serialize out to given binary writer */ + int HairMaterial::writeTo(BinaryWriter &binary) + { + Material::writeTo(binary); + binary.write(eumelanin); + binary.write(alpha); + binary.write(beta_m); + return TYPE_HAIR_MATERIAL; + } + + /*! serialize _in_ from given binary file reader */ + void HairMaterial::readFrom(BinaryReader &binary) + { + Material::readFrom(binary); + binary.read(eumelanin); + binary.read(alpha); + binary.read(beta_m); + } + + /*! serialize out to given binary writer */ diff --git a/pbrtParser/impl/semantic/Geometry.cpp b/pbrtParser/impl/semantic/Geometry.cpp index 62ca7ef..2a33db0 100644 --- a/pbrtParser/impl/semantic/Geometry.cpp +++ b/pbrtParser/impl/semantic/Geometry.cpp @@ -136,7 +136,6 @@ namespace pbrt { { Curve::SP ours = std::make_shared(findOrCreateMaterial(shape->material)); ours->transform = shape->transform.atStart; - // ------------------------------------------------------- // check 'type' // ------------------------------------------------------- @@ -294,24 +293,26 @@ namespace pbrt { if (emittedShapes.find(pbrtShape) != emittedShapes.end()) return emittedShapes[pbrtShape]; - emittedShapes[pbrtShape] = emitShape(pbrtShape); - if (emittedShapes[pbrtShape]) - emittedShapes[pbrtShape]->reverseOrientation = pbrtShape->attributes->reverseOrientation; - /* now, add area light sources */ - if (!pbrtShape->attributes->areaLightSources.empty()) { - std::cout << "Shape has " << pbrtShape->attributes->areaLightSources.size() - << " area light sources..." << std::endl; - assert(pbrtShape->attributes); - auto &areaLights = pbrtShape->attributes->areaLightSources; - if (!areaLights.empty()) { - if (areaLights.size() > 1) - std::cout << "Warning: Shape has more than one area light!?" << std::endl; - assert(emittedShapes[pbrtShape]); - emittedShapes[pbrtShape]->areaLight = parseAreaLight(areaLights[0]); + Shape::SP newShape = emitShape(pbrtShape); + emittedShapes[pbrtShape] = newShape; + if (pbrtShape->attributes) { + newShape->reverseOrientation + = pbrtShape->attributes->reverseOrientation; + /* now, add area light sources */ + + if (!pbrtShape->attributes->areaLightSources.empty()) { + std::cout << "Shape has " << pbrtShape->attributes->areaLightSources.size() + << " area light sources..." << std::endl; + auto &areaLights = pbrtShape->attributes->areaLightSources; + if (!areaLights.empty()) { + if (areaLights.size() > 1) + std::cout << "Warning: Shape has more than one area light!?" << std::endl; + newShape->areaLight = parseAreaLight(areaLights[0]); + } } } - - return emittedShapes[pbrtShape]; + + return newShape; } @@ -324,6 +325,7 @@ namespace pbrt { } Object::SP ourObject = std::make_shared(); + emittedObjects[pbrtObject] = ourObject; ourObject->name = pbrtObject->name; for (auto lightSource : pbrtObject->lightSources) { @@ -331,7 +333,7 @@ namespace pbrt { if (ourLightSource) ourObject->lightSources.push_back(ourLightSource); } - + for (auto shape : pbrtObject->shapes) { Shape::SP ourShape = findOrCreateShape(shape); if (ourShape) @@ -341,7 +343,6 @@ namespace pbrt { for (auto instance : pbrtObject->objectInstances) ourObject->instances.push_back(emitInstance(instance)); - emittedObjects[pbrtObject] = ourObject; return ourObject; } diff --git a/pbrtParser/impl/semantic/Materials.cpp b/pbrtParser/impl/semantic/Materials.cpp index cd48344..b171f77 100644 --- a/pbrtParser/impl/semantic/Materials.cpp +++ b/pbrtParser/impl/semantic/Materials.cpp @@ -23,6 +23,25 @@ namespace pbrt { + Material::SP SemanticParser::createMaterial_hair(pbrt::syntactic::Material::SP in) + { + HairMaterial::SP mat = std::make_shared(in->name); + for (auto it : in->param) { + std::string name = it.first; + if (name == "eumelanin") { + mat->eumelanin = in->getParam1f(name); + } else if (name == "alpha") { + mat->alpha = in->getParam1f(name); + } else if (name == "beta_m") { + mat->beta_m = in->getParam1f(name); + } else if (name == "type") { + /* ignore */ + } else + throw std::runtime_error("as-yet-unhandled hair-material parameter '"+it.first+"'"); + }; + return mat; + } + Material::SP SemanticParser::createMaterial_uber(pbrt::syntactic::Material::SP in) { UberMaterial::SP mat = std::make_shared(in->name); @@ -461,6 +480,10 @@ namespace pbrt { return createMaterial_glass(in); // ================================================================== + if (type == "hair") + return createMaterial_hair(in); + + // ================================================================== #ifndef NDEBUG std::cout << "Warning: un-recognizd material type '"+type+"'" << std::endl; #endif diff --git a/pbrtParser/impl/semantic/SemanticParser.h b/pbrtParser/impl/semantic/SemanticParser.h index 7f5be2a..c245d01 100644 --- a/pbrtParser/impl/semantic/SemanticParser.h +++ b/pbrtParser/impl/semantic/SemanticParser.h @@ -114,6 +114,7 @@ namespace pbrt { /*! @{ type-specific extraction routines (ie, we already know the type, and only have to extract the potential/expected parameters) */ + Material::SP createMaterial_hair(pbrt::syntactic::Material::SP in); Material::SP createMaterial_uber(pbrt::syntactic::Material::SP in); Material::SP createMaterial_metal(pbrt::syntactic::Material::SP in); Material::SP createMaterial_matte(pbrt::syntactic::Material::SP in); diff --git a/pbrtParser/impl/semantic/importPBRT.cpp b/pbrtParser/impl/semantic/importPBRT.cpp index 5108e9a..58f096b 100644 --- a/pbrtParser/impl/semantic/importPBRT.cpp +++ b/pbrtParser/impl/semantic/importPBRT.cpp @@ -507,6 +507,7 @@ namespace pbrt { result = std::make_shared(); result->world = findOrEmitObject(pbrtScene->world); + std::cout << "semantic - done with findoremit" << std::endl; if (!unhandledShapeTypeCounter.empty()) { std::cerr << "WARNING: scene contained some un-handled shapes!" << std::endl; for (auto type : unhandledShapeTypeCounter) diff --git a/pbrtParser/impl/syntactic/Scene.h b/pbrtParser/impl/syntactic/Scene.h index 44a5d52..8f4e31a 100644 --- a/pbrtParser/impl/syntactic/Scene.h +++ b/pbrtParser/impl/syntactic/Scene.h @@ -103,8 +103,8 @@ namespace pbrt { // NOT copyable! Attributes() = default; - Attributes(Attributes&) = delete; - Attributes& operator=(Attributes&) = delete; + Attributes(const Attributes&) = delete; + Attributes& operator=(const Attributes&) = delete; /*! a "Type::SP" shorthand for std::shared_ptr - makes code more concise, and easier to read */ @@ -130,6 +130,24 @@ namespace pbrt { /*! Freeze the current graphics state so that it won't be affected by subsequent changes. Returns the frozen graphics state */ static Attributes::SP freeze(Attributes::SP& graphicsState) { +#if 1 + // iw - this CLONES the state, else I get stack overflow in + // destructor chain: for pbrt-v3-scenes/straight-hair.pbrt i + // get 1M hair shapes, and the shapes::clear() then triggers + // what looks like an infinite (or at least, + // too-deep-for-the-stack) chain of Attribute::~Attribute + // calls. + Attributes::SP newGraphicsState = std::make_shared(); + newGraphicsState->areaLightSources = graphicsState->areaLightSources; + newGraphicsState->mediumInterface = graphicsState->mediumInterface; + newGraphicsState->reverseOrientation = graphicsState->reverseOrientation; + newGraphicsState->parent = graphicsState->parent; + newGraphicsState->prev = graphicsState; + return newGraphicsState; + +#else + // iw, 1/1/20 - this is the code szellman adde to avoid + // un-necessary clones Attributes::SP newGraphicsState = std::make_shared(); newGraphicsState->areaLightSources = graphicsState->areaLightSources; newGraphicsState->mediumInterface = graphicsState->mediumInterface; @@ -141,20 +159,21 @@ namespace pbrt { graphicsState = newGraphicsState; return oldGraphicsState; +#endif } /*! Insert named material */ - void insertNamedMaterial(std::string name, const std::shared_ptr& material) { + void insertNamedMaterial(std::string name, std::shared_ptr material) { namedMaterial[name] = material; } /*! Insert named medium */ - void insertNamedMedium(std::string name, const std::shared_ptr& medium) { + void insertNamedMedium(std::string name, std::shared_ptr medium) { namedMedium[name] = medium; } /*! Insert named texture */ - void insertNamedTexture(std::string name, const std::shared_ptr& texture) { + void insertNamedTexture(std::string name, std::shared_ptr texture) { namedTexture[name] = texture; } @@ -197,7 +216,7 @@ namespace pbrt { /*! get reference to namedTexture */ decltype(namedTexture)& get(std::shared_ptr) { return namedTexture; } - + /*! search this scope for the named item, descend into parent scopes if not found. Also search prior versions */ template @@ -632,14 +651,14 @@ namespace pbrt { typedef std::shared_ptr SP; Object(const std::string &name) : name(name) {} - + struct PBRT_PARSER_INTERFACE Instance { /*! allows for writing pbrt::syntactic::Scene::SP, which is somewhat more concise than std::shared_ptr */ typedef std::shared_ptr SP; - Instance(const std::shared_ptr &object, + Instance(std::shared_ptr object, const Transform &xfm) : object(object), xfm(xfm) {} @@ -680,6 +699,12 @@ namespace pbrt { Scene() : world(std::make_shared("")) {} + virtual ~Scene() + { + std::cout << "destructor in scene .." << std::endl; + world = nullptr; + std::cout << "deleted world" << std::endl; + } /*! parse the given file name, return parsed scene */ static std::shared_ptr parse(const std::string &fileName, const std::string &basePath = ""); diff --git a/pbrtParser/include/pbrtParser/Scene.h b/pbrtParser/include/pbrtParser/Scene.h index c2adc37..1504b70 100644 --- a/pbrtParser/include/pbrtParser/Scene.h +++ b/pbrtParser/include/pbrtParser/Scene.h @@ -454,6 +454,25 @@ namespace pbrt { Texture::SP map_bump; }; + struct HairMaterial : public Material + { + typedef std::shared_ptr SP; + + /*! constructor */ + HairMaterial(const std::string &name = "") : Material(name) {} + + /*! pretty-printer, for debugging */ + virtual std::string toString() const override { return "HairMaterial"; } + /*! serialize out to given binary writer */ + virtual int writeTo(BinaryWriter &) override; + /*! serialize _in_ from given binary file reader */ + virtual void readFrom(BinaryReader &) override; + + float eumelanin { 1.f }; + float beta_m { .25f }; + float alpha { 2.f }; + }; + struct TranslucentMaterial : public Material { typedef std::shared_ptr SP; diff --git a/test-all.sh b/test-all.sh index c8e259f..71c2b03 100755 --- a/test-all.sh +++ b/test-all.sh @@ -174,6 +174,6 @@ for scene in $PBRT_SCENES; do mkdir -p $OUTPUT_PATH/$dir base=`basename $scene .pbrt` ./build/pbrt2pbf $PBRT_SCENE_PATH/$scene -o $OUTPUT_PATH/$dir/$base.pbf - ./build/pbfInfo $OUTPUT_PATH/$dir/$base.pbf + ./build/pbrtInfo $OUTPUT_PATH/$dir/$base.pbf done