better solid angle-weighted hemisphere sampling routine, code cleanups

metadata
Wenzel Jakob 2011-09-06 00:48:36 -04:00
parent d53f7c9196
commit 825acab263
6 changed files with 90 additions and 52 deletions

View File

@ -28,8 +28,9 @@ MTS_NAMESPACE_BEGIN
* \brief Three-dimensional normal data structure
*
* Internally represented using floating point numbers of the chosen
* compile-time precision. The main difference in comparison to <tt>TVector3&lt;Float&gt;</tt>
* is in how instances of <tt>Normal</tt> are treated by linear transformations.
* compile-time precision. The main difference of this data structure
* when compared to \ref TVector3<Float> is in how instances of
* \ref Normal are treated by linear transformations.
*
* \ingroup libcore
* \ingroup libpython

View File

@ -68,8 +68,14 @@
#endif
#elif defined(__APPLE__)
#define __OSX__
#if !defined(_GNU_SOURCE)
#define _GNU_SOURCE
#endif
#elif defined(__linux)
#define __LINUX__
#if !defined(_GNU_SOURCE)
#define _GNU_SOURCE
#endif
#else
#error Unknown OS
#endif

View File

@ -50,7 +50,7 @@ template <typename T> struct TPoint2 {
#if !defined(MTS_DEBUG_UNINITIALIZED)
TPoint2() { }
#else
TPoint2() { x = y = std::numeric_limits<double>::quiet_NaN(); }
TPoint2() { x = y = std::numeric_limits<T>::quiet_NaN(); }
#endif
/// Initialize the point with the specified X, Y and Z components
@ -243,7 +243,7 @@ template <typename T> struct TPoint3 {
#if !defined(MTS_DEBUG_UNINITIALIZED)
TPoint3() { }
#else
TPoint3() { x = y = z = std::numeric_limits<double>::quiet_NaN(); }
TPoint3() { x = y = z = std::numeric_limits<T>::quiet_NaN(); }
#endif
/// Initialize the point with the specified X, Y and Z components
@ -440,7 +440,7 @@ template <typename T> struct TPoint4 {
#if !defined(MTS_DEBUG_UNINITIALIZED)
TPoint4() { }
#else
TPoint4() { x = y = z = w = std::numeric_limits<double>::quiet_NaN(); }
TPoint4() { x = y = z = w = std::numeric_limits<T>::quiet_NaN(); }
#endif
/// Initialize the point with the specified X, Y and Z components

View File

@ -87,11 +87,47 @@ namespace std {
return 1;
return 0;
}
inline void sincos(float theta, float *sin, float *cos) {
float sinValue = sinf(theta);
*sin = sinValue;
*cos = sqrtf(1.0f-sinValue*sinValue);
}
inline void sincos(double theta, double *sin, double *cos) {
double sinValue = sin(theta);
*sin = sinValue;
*cos = sqrt(1.0-sinValue*sinValue);
}
#endif
};
using std::select2nd;
using std::compose1;
#endif
#endif
namespace std {
#if defined(_GNU_SOURCE)
inline void sincos(float theta, float *sin, float *cos) {
::sincosf(theta, sin, cos);
}
inline void sincos(double theta, double *sin, double *cos) {
::sincos(theta, sin, cos);
}
#else
inline void sincos(float theta, float *sin, float *cos) {
float sinValue = sinf(theta);
*sin = sinValue;
*cos = sqrtf(1.0f-sinValue*sinValue);
}
inline void sincos(double theta, double *sin, double *cos) {
double sinValue = sin(theta);
*sin = sinValue;
*cos = sqrt(1.0-sinValue*sinValue);
}
#endif
};
#if defined(WIN32)
inline bool mts_isnan(float f) {

View File

@ -49,7 +49,7 @@ template <typename T> struct TVector2 {
#if !defined(MTS_DEBUG_UNINITIALIZED)
TVector2() { }
#else
TVector2() { x = y = std::numeric_limits<double>::quiet_NaN(); }
TVector2() { x = y = std::numeric_limits<T>::quiet_NaN(); }
#endif
/// Initialize the vector with the specified X and Z components
@ -241,7 +241,7 @@ template <typename T> struct TVector3 {
#if !defined(MTS_DEBUG_UNINITIALIZED)
TVector3() { }
#else
TVector3() { x = y = z = std::numeric_limits<double>::quiet_NaN(); }
TVector3() { x = y = z = std::numeric_limits<T>::quiet_NaN(); }
#endif
/// Initialize the vector with the specified X, Y and Z components
@ -447,7 +447,7 @@ template <typename T> struct TVector4 {
#if !defined(MTS_DEBUG_UNINITIALIZED)
TVector4() { }
#else
TVector4() { x = y = z = w = std::numeric_limits<double>::quiet_NaN(); }
TVector4() { x = y = z = w = std::numeric_limits<T>::quiet_NaN(); }
#endif
/// Initialize the vector with the specified X, Y and Z components

View File

@ -586,60 +586,56 @@ void latinHypercube(Random *random, Float *dest, size_t nSamples, size_t nDim) {
Vector sphericalDirection(Float theta, Float phi) {
Float sinTheta = std::sin(theta);
Float sinTheta, cosTheta, sinPhi, cosPhi;
std::sincos(theta, &sinTheta, &cosTheta);
std::sincos(phi, &sinPhi, &cosPhi);
return Vector(
sinTheta * std::cos(phi),
sinTheta * std::sin(phi),
std::cos(theta)
sinTheta * cosPhi,
sinTheta * sinPhi,
cosTheta
);
}
Vector squareToSphere(const Point2 &sample) {
Float z = 1.0f - 2.0f * sample.y;
Float r = 1.0f - z * z;
r = std::sqrt(std::max((Float) 0, r));
Float phi = 2.0f * M_PI * sample.x;
return Vector(r * std::cos(phi), r * std::sin(phi), z);
Float r = std::sqrt(std::max((Float) 0.0f, 1.0f - z*z));
Float sinPhi, cosPhi;
std::sincos(2.0f * M_PI * sample.x, &sinPhi, &cosPhi);
return Vector(r * cosPhi, r * sinPhi, z);
}
Vector squareToHemisphere(const Point2 &sample) {
Float phi = 2.0f * M_PI * sample.x;
Float r2 = sample.y;
Float tmp = std::sqrt(1-std::min((Float) 1, r2*r2));
Float z = sample.y;
Float tmp = std::sqrt(std::min((Float) 0, 1-z*z));
return Vector(
std::cos(phi) * tmp,
std::sin(phi) * tmp,
r2
);
Float sinPhi, cosPhi;
std::sincos(2.0f * M_PI * sample.x, &sinPhi, &cosPhi);
return Vector(cosPhi * tmp, sinPhi * tmp, z);
}
Vector squareToHemispherePSA(const Point2 &sample) {
Float r = std::sqrt(sample.x);
Float phi = 2.0f * M_PI * sample.y;
Float dirX = r * std::cos(phi);
Float dirY = r * std::sin(phi);
Float z = std::sqrt(1 - std::min((Float) 1, dirX*dirX + dirY*dirY));
Point2 p = squareToDiskConcentric(sample);
Float z = std::sqrt(std::max((Float) 0,
1.0f - p.x*p.x - p.y*p.y));
if (EXPECT_NOT_TAKEN(z == 0)) {
/* Guard against numerical imprecisions */
return normalize(Vector(
dirX, dirY, Epsilon));
}
/* Guard against numerical imprecisions */
if (EXPECT_NOT_TAKEN(z == 0))
z = 1e-10f;
return Vector(
dirX, dirY, z
);
return Vector(p.x, p.y, z);
}
Point2 squareToDisk(const Point2 &sample) {
Float r = std::sqrt(sample.x);
Float phi = 2.0f * M_PI * sample.y;
Float dirX = r * std::cos(phi);
Float dirY = r * std::sin(phi);
Float sinPhi, cosPhi;
std::sincos(2.0f * M_PI * sample.y, &sinPhi, &cosPhi);
return Point2(
dirX, dirY
cosPhi * r,
sinPhi * r
);
}
@ -687,10 +683,10 @@ Point2 squareToDiskConcentric(const Point2 &sample) {
else
coords = Point2(-r2, (M_PI/4.0f) * (6.0f - r1/r2));
}
return Point2(
coords.x*std::cos(coords.y),
coords.x*std::sin(coords.y)
);
Point2 result;
std::sincos(coords.y, &result.y, &result.x);
return result*coords.x;
}
Float squareToConePdf(Float cosCutoff) {
@ -706,12 +702,11 @@ Vector squareToCone(Float cosCutoff, const Point2 &sample) {
}
Point2 squareToStdNormal(const Point2 &sample) {
Float tmp1 = std::sqrt(-2 * std::log(1-sample.x)),
tmp2 = 2 * M_PI * sample.y;
return Point2(
tmp1 * std::cos(tmp2),
tmp1 * std::sin(tmp2)
);
Float r = std::sqrt(-2 * std::log(1-sample.x)),
phi = 2 * M_PI * sample.y;
Point2 result;
std::sincos(phi, &result.y, &result.x);
return result * r;
}
Float lanczosSinc(Float t, Float tau) {