Parcourir la source

Add PBRT_MTL_HACK writeup, patch

Matt Pharr il y a 7 ans
Parent
commit
f7920f3826
2 fichiers modifiés avec 113 ajouts et 22 suppressions
  1. 35 22
      README.md.html
  2. 78 0
      html/mtl.patch.txt

+ 35 - 22
README.md.html

@@ -258,7 +258,7 @@ help with improvements in this area!)
 The `exporters/cinema4d` directory in the pbrt-v3 distribution provides an
 exporter from Cinema 4D. This exporter was developed to export the amazing
 "landscape" scene that is on the book's front cover from Cinema 4D, so thus
-should be up to date with respect to pbrt's material models and rendering
+is up to date with respect to pbrt's material models and rendering
 settings. We have seen good results with using this exporter for other
 Cinema 4D scenes.
 
@@ -276,7 +276,8 @@ $ obj2pbrt scene.obj scene.pbrt
 If there is an accompanying material description file (e.g. `scene.mtl`),
 the values in it will be roughly mapped to corresponding pbrt materials.
 You will likely need to manually edit and tune the materials in the
-generated pbrt file in order to achieve reasonably good-looking results.
+generated pbrt file in order to achieve reasonably good-looking
+results.
 
 Note that OBJ files only describe scene geometry; they don't include camera
 specifications or descriptions of light sources. (Thus, the generated pbrt
@@ -349,9 +350,11 @@ origin you've chosen as the basis for specifying a `LookAt` transformation
 for a more conventional camera model.
 
 While placing the camera, it can be helpful to have a point light source at
-the camera's position. Adding the following light source to your scene file
-does this in a way that ensures that the light moves appropriately to
-wherever the camera has been placed.
+the camera's position. Adding a light source like the following to your
+scene file does this in a way that ensures that the light moves
+appropriately to wherever the camera has been placed. (You may need to
+scale the intensity up or down for good results--remember the
+radius-squared falloff!
 
 ```
 AttributeBegin
@@ -362,23 +365,33 @@ AttributeEnd
 
 Once the camera is placed, we have found that it's next useful to set up
 approximate light sources. For outdoor scenes, a good HDR environment map
-is often all that is needed for lighting. For indoor scenes, you may want a
-combination of an environment map for the outside and point and/or area
-light sources for interior lights. You may find it useful to examine the
-scene in the modeling system that it came from to determine which geometry
-corresponds to area light sources and to try adding `AreaLightSource`
-properties to those. (Note that in pbrt, area light sources only emit
-lights on the side that the surface normal points; you may need a
-`ReverseOrientation` directive to make the light come out in the right
-direction.
-
-Given good lighting, the next step is to tune the materials. It can be
-helpful to pick a material and set it to an extreme value (such as a
-"matte" material that is pure red) and render the scene; this quickly shows
-which geometric models have that material associated with it. As you do
-this, watch for objects that are missing texture maps and re-add
-them. (The good news is that such objects generally do have correct texture
-coordinates with them. 
+is often all that is needed for lighting. (You may want to consider using
+`imgtool makesky` to make a realistic HDR sky environment map.)
+
+For indoor scenes, you may want a combination of an environment map for the
+outside and point and/or area light sources for interior lights. You may
+find it useful to examine the scene in the modeling system that it came
+from to determine which geometry corresponds to area light sources and to
+try adding `AreaLightSource` properties to those. (Note that in pbrt, area
+light sources only emit lights on the side that the surface normal points;
+you may need a `ReverseOrientation` directive to make the light come out in
+the right direction.)
+
+Given good lighting, the next step is to tune the materials (or set them
+from scratch). It can be helpful to pick a material and set it to an
+extreme value (such as a "matte" material that is pure red) and render the
+scene; this quickly shows which geometric models have that material
+associated with it. Alternatively, consdier applying this
+[patch](html/mtl.patch.txt) to your pbrt source tree; after rebuilding
+pbrt, if you set the `PBRT_MTL_HACK` environment variable, rendering the
+scene will cause a separate image to be generated for each `NamedMaterial`
+in the scene, with a filename corresponding to the material name. Each
+image will only include the objects with that material.
+
+As you figure out which material names correspond to what geometry, watch
+for objects that are missing texture maps and re-add them. (The good news
+is that such objects generally do have correct texture coordinates with
+them.
 
 # Submitting Updates
 

+ 78 - 0
html/mtl.patch.txt

@@ -0,0 +1,78 @@
+diff --git a/src/core/api.cpp b/src/core/api.cpp
+index e0c4b4a..b275b85 100644
+--- a/src/core/api.cpp
++++ b/src/core/api.cpp
+@@ -234,6 +234,9 @@ static std::vector<uint32_t> pushedActiveTransformBits;
+ static TransformCache transformCache;
+ int catIndentCount = 0;
+ 
++static bool renderEachMaterial = getenv("PBRT_MTL_HACK");
++static std::map<std::string, std::shared_ptr<Material>>::iterator namedMaterialsIter;
++
+ // API Forward Declarations
+ std::vector<std::shared_ptr<Shape>> MakeShapes(const std::string &name,
+                                                const Transform *ObjectToWorld,
+@@ -1346,6 +1349,14 @@ void pbrtWorldEnd() {
+     // Create scene and render
+     if (PbrtOptions.cat || PbrtOptions.toPly) {
+         printf("%*sWorldEnd\n", catIndentCount, "");
++    } else if (renderEachMaterial) {
++      for (namedMaterialsIter = graphicsState.namedMaterials.begin();
++           namedMaterialsIter != graphicsState.namedMaterials.end(); ++namedMaterialsIter) {
++        std::unique_ptr<Integrator> integrator(renderOptions->MakeIntegrator());
++        std::unique_ptr<Scene> scene(renderOptions->MakeScene());
++        if (scene && integrator) integrator->Render(*scene);
++      }
++      // TODO? render stuff with no material bound?
+     } else {
+         std::unique_ptr<Integrator> integrator(renderOptions->MakeIntegrator());
+         std::unique_ptr<Scene> scene(renderOptions->MakeScene());
+@@ -1371,13 +1382,24 @@ void pbrtWorldEnd() {
+ }
+ 
+ Scene *RenderOptions::MakeScene() {
+-    std::shared_ptr<Primitive> accelerator =
+-        MakeAccelerator(AcceleratorName, primitives, AcceleratorParams);
++    std::shared_ptr<Primitive> accelerator;
++    if (renderEachMaterial) {
++        std::vector<std::shared_ptr<Primitive>> filteredPrims;
++        std::copy_if(primitives.begin(), primitives.end(), std::back_inserter(filteredPrims),
++                     [](const std::shared_ptr<Primitive> &p) -> bool {
++                       return p->GetMaterial() == namedMaterialsIter->second.get();
++                     });
++        accelerator = MakeAccelerator(AcceleratorName, filteredPrims, AcceleratorParams);
++    } else {
++        accelerator = MakeAccelerator(AcceleratorName, primitives, AcceleratorParams);
++    }
+     if (!accelerator) accelerator = std::make_shared<BVHAccel>(primitives);
+     Scene *scene = new Scene(accelerator, lights);
+-    // Erase primitives and lights from _RenderOptions_
+-    primitives.erase(primitives.begin(), primitives.end());
+-    lights.erase(lights.begin(), lights.end());
++    if (!renderEachMaterial) {
++      // Erase primitives and lights from _RenderOptions_
++      primitives.erase(primitives.begin(), primitives.end());
++      lights.erase(lights.begin(), lights.end());
++    }
+     return scene;
+ }
+ 
+@@ -1427,7 +1449,17 @@ Integrator *RenderOptions::MakeIntegrator() const {
+ 
+ Camera *RenderOptions::MakeCamera() const {
+     std::unique_ptr<Filter> filter = MakeFilter(FilterName, FilterParams);
+-    Film *film = MakeFilm(FilmName, FilmParams, std::move(filter));
++    Film *film = nullptr;
++    if (renderEachMaterial) {
++      ParamSet fp = FilmParams;
++      std::unique_ptr<std::string[]> fns(new std::string[1]);
++      fns[0] = namedMaterialsIter->first + ".exr";
++      fp.AddString("filename", std::move(fns), 1);
++      std::unique_ptr<Filter> box(new BoxFilter({0.5f, 0.5f}));
++      film = MakeFilm(FilmName, fp, std::move(box));
++    } else
++      film = MakeFilm(FilmName, FilmParams, std::move(filter));
++
+     if (!film) {
+         Error("Unable to create film.");
+         return nullptr;