vMF distribution class improvements, python bindings for it
parent
006c26891f
commit
4e8015f787
|
@ -28,7 +28,9 @@ MTS_NAMESPACE_BEGIN
|
||||||
* \brief Von Mises-Fisher distribution on the 2-sphere
|
* \brief Von Mises-Fisher distribution on the 2-sphere
|
||||||
*
|
*
|
||||||
* This is a basic implementation, which assumes that the
|
* This is a basic implementation, which assumes that the
|
||||||
* distribution is centered around the Z-axis.
|
* distribution is centered around the Z-axis. All provided
|
||||||
|
* functions are implemented in such a way that they avoid
|
||||||
|
* issues with numerical overflow.
|
||||||
*
|
*
|
||||||
* \author Wenzel Jakob
|
* \author Wenzel Jakob
|
||||||
* \ingroup libcore
|
* \ingroup libcore
|
||||||
|
@ -39,13 +41,21 @@ public:
|
||||||
* \brief Create a new von Mises-Fisher distribution
|
* \brief Create a new von Mises-Fisher distribution
|
||||||
* with the given concentration parameter
|
* with the given concentration parameter
|
||||||
*/
|
*/
|
||||||
VonMisesFisherDistr(Float kappa = 0);
|
explicit inline VonMisesFisherDistr(Float kappa = 0) : m_kappa(kappa) { }
|
||||||
|
|
||||||
|
/// Return the concentration parameter kappa
|
||||||
|
inline void setKappa(Float kappa) {
|
||||||
|
m_kappa = kappa;
|
||||||
|
}
|
||||||
|
|
||||||
/// Return the concentration parameter kappa
|
/// Return the concentration parameter kappa
|
||||||
inline Float getKappa() const {
|
inline Float getKappa() const {
|
||||||
return m_kappa;
|
return m_kappa;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the mean cosine of the distribution
|
||||||
|
Float getMeanCosine() const;
|
||||||
|
|
||||||
/// Evaluate the distribution for a given value of cos(theta)
|
/// Evaluate the distribution for a given value of cos(theta)
|
||||||
Float eval(Float cosTheta) const;
|
Float eval(Float cosTheta) const;
|
||||||
|
|
||||||
|
@ -57,12 +67,21 @@ public:
|
||||||
*/
|
*/
|
||||||
Vector sample(const Point2 &sample) const;
|
Vector sample(const Point2 &sample) const;
|
||||||
|
|
||||||
|
/// Return a string representation
|
||||||
|
std::string toString() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Compute an appropriate concentration parameter so that
|
* \brief Compute an appropriate concentration parameter so that
|
||||||
* the associated vMF distribution takes on the value \c x at its peak
|
* the associated vMF distribution takes on the value \c x at its peak
|
||||||
*/
|
*/
|
||||||
static Float forPeakValue(Float x);
|
static Float forPeakValue(Float x);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Compute an appropriate concentration parameter so that
|
||||||
|
* the associated vMF distribution has the mean cosine \c g.
|
||||||
|
*/
|
||||||
|
static Float forMeanCosine(Float g);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Compute an concentration parameter that approximately
|
* \brief Compute an concentration parameter that approximately
|
||||||
* corresponds to the spherical convolution of two vMF distributions.
|
* corresponds to the spherical convolution of two vMF distributions.
|
||||||
|
|
|
@ -18,11 +18,11 @@
|
||||||
|
|
||||||
#include <mitsuba/core/vmf.h>
|
#include <mitsuba/core/vmf.h>
|
||||||
#include <mitsuba/core/warp.h>
|
#include <mitsuba/core/warp.h>
|
||||||
|
#include <mitsuba/core/brent.h>
|
||||||
|
#include <boost/bind.hpp>
|
||||||
|
|
||||||
MTS_NAMESPACE_BEGIN
|
MTS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
VonMisesFisherDistr::VonMisesFisherDistr(Float kappa): m_kappa(kappa) { }
|
|
||||||
|
|
||||||
Float VonMisesFisherDistr::eval(Float cosTheta) const {
|
Float VonMisesFisherDistr::eval(Float cosTheta) const {
|
||||||
if (m_kappa == 0.0f)
|
if (m_kappa == 0.0f)
|
||||||
return INV_FOURPI;
|
return INV_FOURPI;
|
||||||
|
@ -63,22 +63,23 @@ Vector VonMisesFisherDistr::sample(const Point2 &sample) const {
|
||||||
sinPhi * sinTheta, cosTheta);
|
sinPhi * sinTheta, cosTheta);
|
||||||
}
|
}
|
||||||
|
|
||||||
Float VonMisesFisherDistr::forPeakValue(Float x) {
|
Float VonMisesFisherDistr::getMeanCosine() const {
|
||||||
if (x < INV_FOURPI) {
|
if (m_kappa == 0)
|
||||||
return 0.0f;
|
return 0;
|
||||||
} else if (x > 0.795) {
|
Float coth = m_kappa > 6 ? 1 : ((std::exp(2*m_kappa)+1)/(std::exp(2*m_kappa)-1));
|
||||||
return 2 * M_PI * x;
|
return coth-1/m_kappa;
|
||||||
} else {
|
|
||||||
return std::max((Float) 0.0f,
|
|
||||||
(168.479f * x * x + 16.4585f * x - 2.39942f) /
|
|
||||||
(-1.12718f * x * x + 29.1433f * x + 1.0f));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Float A3(Float kappa) {
|
static Float A3(Float kappa) {
|
||||||
return 1/ std::tanh(kappa) - 1 / kappa;
|
return 1/ std::tanh(kappa) - 1 / kappa;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string VonMisesFisherDistr::toString() const {
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "VonMisesFisherDistr[kappa=" << m_kappa << "]";
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
static Float dA3(Float kappa) {
|
static Float dA3(Float kappa) {
|
||||||
Float csch = 2.0f /
|
Float csch = 2.0f /
|
||||||
(math::fastexp(kappa)-math::fastexp(-kappa));
|
(math::fastexp(kappa)-math::fastexp(-kappa));
|
||||||
|
@ -110,4 +111,33 @@ Float VonMisesFisherDistr::convolve(Float kappa1, Float kappa2) {
|
||||||
return A3inv(A3(kappa1) * A3(kappa2), std::min(kappa1, kappa2));
|
return A3inv(A3(kappa1) * A3(kappa2), std::min(kappa1, kappa2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Float VonMisesFisherDistr::forPeakValue(Float x) {
|
||||||
|
if (x < INV_FOURPI) {
|
||||||
|
return 0.0f;
|
||||||
|
} else if (x > 0.795) {
|
||||||
|
return 2 * M_PI * x;
|
||||||
|
} else {
|
||||||
|
return std::max((Float) 0.0f,
|
||||||
|
(168.479f * x * x + 16.4585f * x - 2.39942f) /
|
||||||
|
(-1.12718f * x * x + 29.1433f * x + 1.0f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Float meanCosineFunctor(Float kappa, Float g) {
|
||||||
|
return VonMisesFisherDistr(kappa).getMeanCosine()-g;
|
||||||
|
}
|
||||||
|
|
||||||
|
Float VonMisesFisherDistr::forMeanCosine(Float g) {
|
||||||
|
if (g == 0)
|
||||||
|
return 0;
|
||||||
|
else if (g < 0)
|
||||||
|
SLog(EError, "Error: vMF distribution cannot be created for g<0.");
|
||||||
|
|
||||||
|
BrentSolver brentSolver(100, 1e-6f);
|
||||||
|
BrentSolver::Result result = brentSolver.solve(
|
||||||
|
boost::bind(&meanCosineFunctor, _1, g), 0, 1000);
|
||||||
|
SAssert(result.success);
|
||||||
|
return result.x;
|
||||||
|
}
|
||||||
|
|
||||||
MTS_NAMESPACE_END
|
MTS_NAMESPACE_END
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include <mitsuba/core/mstream.h>
|
#include <mitsuba/core/mstream.h>
|
||||||
#include <mitsuba/core/cstream.h>
|
#include <mitsuba/core/cstream.h>
|
||||||
#include <mitsuba/core/qmc.h>
|
#include <mitsuba/core/qmc.h>
|
||||||
|
#include <mitsuba/core/vmf.h>
|
||||||
#include <mitsuba/core/shvector.h>
|
#include <mitsuba/core/shvector.h>
|
||||||
#include <mitsuba/core/sshstream.h>
|
#include <mitsuba/core/sshstream.h>
|
||||||
#include <mitsuba/render/scenehandler.h>
|
#include <mitsuba/render/scenehandler.h>
|
||||||
|
@ -2251,6 +2252,20 @@ void export_core() {
|
||||||
.def("getMillisecondsSinceStart", &Timer::getMillisecondsSinceStart)
|
.def("getMillisecondsSinceStart", &Timer::getMillisecondsSinceStart)
|
||||||
.def("getSecondsSinceStart", &Timer::getSecondsSinceStart);
|
.def("getSecondsSinceStart", &Timer::getSecondsSinceStart);
|
||||||
|
|
||||||
|
BP_STRUCT(VonMisesFisherDistr, bp::init<Float>())
|
||||||
|
.def("getKappa", &VonMisesFisherDistr::getKappa)
|
||||||
|
.def("setKappa", &VonMisesFisherDistr::setKappa)
|
||||||
|
.def("eval", &VonMisesFisherDistr::eval)
|
||||||
|
.def("getMeanCosine", &VonMisesFisherDistr::getMeanCosine)
|
||||||
|
.def("sample", &VonMisesFisherDistr::sample, BP_RETURN_VALUE)
|
||||||
|
.def("forMeanCosine", &VonMisesFisherDistr::forMeanCosine)
|
||||||
|
.def("forPeakValue", &VonMisesFisherDistr::forPeakValue)
|
||||||
|
.def("convolve", &VonMisesFisherDistr::convolve)
|
||||||
|
.def("__repr__", &VonMisesFisherDistr::toString)
|
||||||
|
.staticmethod("forMeanCosine")
|
||||||
|
.staticmethod("forPeakValue")
|
||||||
|
.staticmethod("convolve");
|
||||||
|
|
||||||
bp::detail::current_scope = oldScope;
|
bp::detail::current_scope = oldScope;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue