diff --git a/include/mitsuba/core/vmf.h b/include/mitsuba/core/vmf.h index f9568c5e..3a7b23e1 100644 --- a/include/mitsuba/core/vmf.h +++ b/include/mitsuba/core/vmf.h @@ -76,6 +76,15 @@ public: */ static Float forPeakValue(Float x); + /** + * \brief Estimate the vMF concentration parameter + * based on the length of the mean vector that is produced + * by simply averaging a set of sampled directions + * + * This is an unbiased estimator [Banerjee et al. 05] + */ + static Float forMeanLength(Float length); + /** * \brief Compute an appropriate concentration parameter so that * the associated vMF distribution has the mean cosine \c g. diff --git a/src/libcore/vmf.cpp b/src/libcore/vmf.cpp index 7d5a213b..8626fdff 100644 --- a/src/libcore/vmf.cpp +++ b/src/libcore/vmf.cpp @@ -127,6 +127,10 @@ static Float meanCosineFunctor(Float kappa, Float g) { return VonMisesFisherDistr(kappa).getMeanCosine()-g; } +Float VonMisesFisherDistr::forMeanLength(Float l) { + return (3*l - l*l*l) / (1-l*l); +} + Float VonMisesFisherDistr::forMeanCosine(Float g) { if (g == 0) return 0; diff --git a/src/libpython/core.cpp b/src/libpython/core.cpp index cbe0ff07..7d576248 100644 --- a/src/libpython/core.cpp +++ b/src/libpython/core.cpp @@ -512,6 +512,8 @@ static Ray transform_mul_ray(Transform *transform, const Ray &ray) { return tran static Transform transform_mul_transform(Transform *transform, const Transform &other) { return *transform * other; } bp::object cast(ConfigurableObject *obj) { + if (obj == NULL) + return bp::object(); const Class *cls = obj->getClass(); #define TryCast(ClassName) if (cls->derivesFrom(MTS_CLASS(ClassName))) \ return bp::object(ref(static_cast(obj))) @@ -2537,6 +2539,7 @@ void export_core() { .def("getMeanCosine", &VonMisesFisherDistr::getMeanCosine) .def("sample", &VonMisesFisherDistr::sample, BP_RETURN_VALUE) .def("forMeanCosine", &VonMisesFisherDistr::forMeanCosine) + .def("forMeanLength", &VonMisesFisherDistr::forMeanLength) .def("forPeakValue", &VonMisesFisherDistr::forPeakValue) .def("convolve", &VonMisesFisherDistr::convolve) .def("__repr__", &VonMisesFisherDistr::toString) diff --git a/src/libpython/render.cpp b/src/libpython/render.cpp index d78dc3a0..3f2d70d2 100644 --- a/src/libpython/render.cpp +++ b/src/libpython/render.cpp @@ -55,6 +55,10 @@ static Shape *shape_getShapeGroup(Shape *shape) { return static_cast(shape)->getShapeGroup(); } +static bp::object shape_getElement(Shape *shape, int idx) { + return cast(shape->getElement(idx)); +} + static AABB shapekdtree_getAABB(const ShapeKDTree *kdtree) { return kdtree->getAABB(); } @@ -519,7 +523,7 @@ void export_render() { BP_CLASS(Shape, ConfigurableObject, bp::no_init) .def("getName", &Shape::getName, BP_RETURN_VALUE) .def("isCompound", &Shape::isCompound) - .def("getElement", &Shape::getElement, BP_RETURN_VALUE) + .def("getElement", shape_getElement) .def("getSurfaceArea", &Shape::getSurfaceArea) .def("getAABB", &Shape::getAABB, BP_RETURN_VALUE) .def("getClippedAABB", &Shape::getClippedAABB, BP_RETURN_VALUE) diff --git a/src/sensors/orthographic.cpp b/src/sensors/orthographic.cpp index 5b0e9e26..73247257 100644 --- a/src/sensors/orthographic.cpp +++ b/src/sensors/orthographic.cpp @@ -224,12 +224,12 @@ public: Float pdfDirection(const DirectionSamplingRecord &dRec, const PositionSamplingRecord &pRec) const { - return (pRec.measure == EDiscrete) ? 1.0f : 0.0f; + return (dRec.measure == EDiscrete) ? 1.0f : 0.0f; } Spectrum evalDirection(const DirectionSamplingRecord &dRec, const PositionSamplingRecord &pRec) const { - return Spectrum((pRec.measure == EDiscrete) ? 1.0f : 0.0f); + return Spectrum((dRec.measure == EDiscrete) ? 1.0f : 0.0f); } Spectrum sampleDirect(DirectSamplingRecord &dRec, const Point2 &) const {