partial merge with the -ctrewrite branch

metadata
Wenzel Jakob 2011-04-21 01:12:08 +02:00
parent a3f7922f0f
commit c511567250
18 changed files with 173 additions and 86 deletions

View File

@ -101,6 +101,11 @@ public:
*/ */
Random(); Random();
/**
* \brief Construct a random generator with a custom seed
*/
Random(uint64_t seed);
/// Construct a new random generator seeded from a pre-existing one /// Construct a new random generator seeded from a pre-existing one
Random(Random *random); Random(Random *random);

View File

@ -113,7 +113,7 @@ struct Ray {
/// Return a string representation of this ray /// Return a string representation of this ray
inline std::string toString() const { inline std::string toString() const {
std::ostringstream oss; std::ostringstream oss;
oss << "Ray[orig=" << o.toString() << ", dest=" oss << "Ray[orig=" << o.toString() << ", dir="
<< d.toString() << ", mint=" << mint << d.toString() << ", mint=" << mint
<< ", maxt=" << maxt << ", time=" << time << "]"; << ", maxt=" << maxt << ", time=" << time << "]";
return oss.str(); return oss.str();
@ -188,7 +188,7 @@ struct RayDifferential : public Ray {
std::ostringstream oss; std::ostringstream oss;
oss << "RayDifferential[" << endl oss << "RayDifferential[" << endl
<< " orig = " << o.toString() << "," << endl << " orig = " << o.toString() << "," << endl
<< " dest = " << d.toString() << "," << endl << " dir = " << d.toString() << "," << endl
<< " mint = " << mint << "," << endl << " mint = " << mint << "," << endl
<< " maxt = " << maxt << "," << endl << " maxt = " << maxt << "," << endl
<< " time = " << time << "," << endl << " time = " << time << "," << endl

View File

@ -36,17 +36,26 @@ public:
EClamp EClamp
}; };
enum EFilterType {
/// Elliptically weighted average
EEWA,
/// Trilinear filtering
ETrilinear,
/// No filtering
ENone
};
/** /**
* Construct a new mip-map from the given texture. Does not * Construct a new mip-map from the given texture. Does not
* need to have a power-of-two size. * need to have a power-of-two size.
*/ */
MIPMap(int width, int height, Spectrum *pixels, MIPMap(int width, int height, Spectrum *pixels,
bool isotropic = false, EWrapMode wrapMode = ERepeat, EFilterType filterType = EEWA, EWrapMode wrapMode = ERepeat,
Float maxAnisotropy = 8.0f); Float maxAnisotropy = 8.0f);
/// Construct a mip map from a HDR bitmap /// Construct a mip map from a HDR bitmap
static ref<MIPMap> fromBitmap(Bitmap *bitmap, static ref<MIPMap> fromBitmap(Bitmap *bitmap,
bool isotropic = false, EWrapMode wrapMode = ERepeat, EFilterType filterType = EEWA, EWrapMode wrapMode = ERepeat,
Float maxAnisotropy = 8.0f); Float maxAnisotropy = 8.0f);
/// Do a mip-map lookup at the appropriate level /// Do a mip-map lookup at the appropriate level
@ -115,7 +124,7 @@ private:
int *m_levelWidth; int *m_levelWidth;
int *m_levelHeight; int *m_levelHeight;
Spectrum **m_pyramid; Spectrum **m_pyramid;
bool m_isotropic; EFilterType m_filterType;
EWrapMode m_wrapMode; EWrapMode m_wrapMode;
Float *m_weightLut; Float *m_weightLut;
Float m_maxAnisotropy; Float m_maxAnisotropy;

View File

@ -195,8 +195,12 @@ public:
virtual Shape *getElement(int i); virtual Shape *getElement(int i);
/// Return the shape's surface area /**
virtual Float getSurfaceArea() const = 0; * \brief Return the shape's surface area
*
* The default implementation throws an exception
*/
virtual Float getSurfaceArea() const;
/// Return a bounding box containing the shape /// Return a bounding box containing the shape
virtual AABB getAABB() const = 0; virtual AABB getAABB() const = 0;

View File

@ -39,6 +39,9 @@ public:
/// Return the component-wise maximum of the texture over its domain /// Return the component-wise maximum of the texture over its domain
virtual Spectrum getMaximum() const = 0; virtual Spectrum getMaximum() const = 0;
/// Return the resolution in pixels, if applicable
virtual Vector3i getResolution() const;
/** /**
* \brief Does this texture do pre-filtering when ray * \brief Does this texture do pre-filtering when ray
* differentials are available? * differentials are available?
@ -64,11 +67,6 @@ public:
/// Serialize to a binary data stream /// Serialize to a binary data stream
virtual void serialize(Stream *stream, InstanceManager *manager) const; virtual void serialize(Stream *stream, InstanceManager *manager) const;
MTS_DECLARE_CLASS()
protected:
Texture2D(const Properties &props);
Texture2D(Stream *stream, InstanceManager *manager);
/// Texture2D subclass must provide this function /// Texture2D subclass must provide this function
virtual Spectrum getValue(const Point2 &uv) const = 0; virtual Spectrum getValue(const Point2 &uv) const = 0;
@ -76,6 +74,11 @@ protected:
virtual Spectrum getValue(const Point2 &uv, Float dudx, virtual Spectrum getValue(const Point2 &uv, Float dudx,
Float dudy, Float dvdx, Float dvdy) const = 0; Float dudy, Float dvdx, Float dvdy) const = 0;
MTS_DECLARE_CLASS()
protected:
Texture2D(const Properties &props);
Texture2D(Stream *stream, InstanceManager *manager);
virtual ~Texture2D(); virtual ~Texture2D();
protected: protected:
Point2 m_uvOffset; Point2 m_uvOffset;

View File

@ -13,5 +13,6 @@ plugins += env.SharedLibrary('#plugins/roughglass', ['roughglass.cpp'])
plugins += env.SharedLibrary('#plugins/roughmetal', ['roughmetal.cpp']) plugins += env.SharedLibrary('#plugins/roughmetal', ['roughmetal.cpp'])
plugins += env.SharedLibrary('#plugins/composite', ['composite.cpp']) plugins += env.SharedLibrary('#plugins/composite', ['composite.cpp'])
plugins += env.SharedLibrary('#plugins/twosided', ['twosided.cpp']) plugins += env.SharedLibrary('#plugins/twosided', ['twosided.cpp'])
plugins += env.SharedLibrary('#plugins/irawan', ['irawan.cpp'])
Export('plugins') Export('plugins')

View File

@ -116,7 +116,7 @@ public:
std::string toString() const { std::string toString() const {
std::ostringstream oss; std::ostringstream oss;
oss << "Microfacet[" << endl oss << "Lambertian[" << endl
<< " reflectance = " << indent(m_reflectance->toString()) << endl << " reflectance = " << indent(m_reflectance->toString()) << endl
<< "]"; << "]";
return oss.str(); return oss.str();

View File

@ -80,6 +80,11 @@ Random::Random(Random *random) {
seed(random); seed(random);
} }
Random::Random(uint64_t seedval) {
mti=MT_N+1; /* mti==N+1 means mt[N] is not initialized */
seed(seedval);
}
Random::Random(Stream *stream, InstanceManager *manager) Random::Random(Stream *stream, InstanceManager *manager)
: SerializableObject(stream, manager) { : SerializableObject(stream, manager) {
mti = stream->readInt(); mti = stream->readInt();

View File

@ -26,12 +26,12 @@ static StatsCounter ewaLookups("Texture", "EWA texture lookups");
/* Isotropic/anisotropic EWA mip-map texture map class based on PBRT */ /* Isotropic/anisotropic EWA mip-map texture map class based on PBRT */
MIPMap::MIPMap(int width, int height, Spectrum *pixels, MIPMap::MIPMap(int width, int height, Spectrum *pixels,
bool isotropic, EWrapMode wrapMode, Float maxAnisotropy) EFilterType filterType, EWrapMode wrapMode, Float maxAnisotropy)
: m_width(width), m_height(height), m_isotropic(isotropic), : m_width(width), m_height(height), m_filterType(filterType),
m_wrapMode(wrapMode), m_maxAnisotropy(maxAnisotropy) { m_wrapMode(wrapMode), m_maxAnisotropy(maxAnisotropy) {
Spectrum *texture = pixels; Spectrum *texture = pixels;
if (!isPow2(width) || !isPow2(height)) { if (filterType != ENone && (!isPow2(width) || !isPow2(height))) {
m_width = (int) roundToPow2((uint32_t) width); m_width = (int) roundToPow2((uint32_t) width);
m_height = (int) roundToPow2((uint32_t) height); m_height = (int) roundToPow2((uint32_t) height);
@ -87,7 +87,11 @@ MIPMap::MIPMap(int width, int height, Spectrum *pixels,
delete[] texture1; delete[] texture1;
} }
if (m_filterType != ENone)
m_levels = 1 + log2i((uint32_t) std::max(width, height)); m_levels = 1 + log2i((uint32_t) std::max(width, height));
else
m_levels = 1;
m_pyramid = new Spectrum*[m_levels]; m_pyramid = new Spectrum*[m_levels];
m_pyramid[0] = texture; m_pyramid[0] = texture;
m_levelWidth = new int[m_levels]; m_levelWidth = new int[m_levels];
@ -111,7 +115,7 @@ MIPMap::MIPMap(int width, int height, Spectrum *pixels,
} }
} }
if (!isotropic) { if (m_filterType == EEWA) {
m_weightLut = static_cast<Float *>(allocAligned(sizeof(Float)*MIPMAP_LUTSIZE)); m_weightLut = static_cast<Float *>(allocAligned(sizeof(Float)*MIPMAP_LUTSIZE));
for (int i=0; i<MIPMAP_LUTSIZE; ++i) { for (int i=0; i<MIPMAP_LUTSIZE; ++i) {
Float pos = (Float) i / (Float) (MIPMAP_LUTSIZE-1); Float pos = (Float) i / (Float) (MIPMAP_LUTSIZE-1);
@ -121,7 +125,7 @@ MIPMap::MIPMap(int width, int height, Spectrum *pixels,
} }
MIPMap::~MIPMap() { MIPMap::~MIPMap() {
if (!m_isotropic) if (m_filterType == EEWA)
freeAligned(m_weightLut); freeAligned(m_weightLut);
for (int i=0; i<m_levels; i++) for (int i=0; i<m_levels; i++)
delete[] m_pyramid[i]; delete[] m_pyramid[i];
@ -149,7 +153,7 @@ Spectrum MIPMap::getMaximum() const {
return max; return max;
} }
ref<MIPMap> MIPMap::fromBitmap(Bitmap *bitmap, bool isotropic, ref<MIPMap> MIPMap::fromBitmap(Bitmap *bitmap, EFilterType filterType,
EWrapMode wrapMode, Float maxAnisotropy) { EWrapMode wrapMode, Float maxAnisotropy) {
int width = bitmap->getWidth(); int width = bitmap->getWidth();
int height = bitmap->getHeight(); int height = bitmap->getHeight();
@ -169,7 +173,7 @@ ref<MIPMap> MIPMap::fromBitmap(Bitmap *bitmap, bool isotropic,
} }
return new MIPMap(width, height, pixels, return new MIPMap(width, height, pixels,
isotropic, wrapMode, maxAnisotropy); filterType, wrapMode, maxAnisotropy);
} }
MIPMap::ResampleWeight *MIPMap::resampleWeights(int oldRes, int newRes) const { MIPMap::ResampleWeight *MIPMap::resampleWeights(int oldRes, int newRes) const {
@ -179,7 +183,7 @@ MIPMap::ResampleWeight *MIPMap::resampleWeights(int oldRes, int newRes) const {
ResampleWeight *weights = new ResampleWeight[newRes]; ResampleWeight *weights = new ResampleWeight[newRes];
for (int i=0; i<newRes; i++) { for (int i=0; i<newRes; i++) {
Float center = (i + .5f) * oldRes / newRes; Float center = (i + .5f) * oldRes / newRes;
weights[i].firstTexel = (int) std::floor(center - filterWidth + (Float) 0.5f); weights[i].firstTexel = floorToInt(center - filterWidth + (Float) 0.5f);
Float weightSum = 0; Float weightSum = 0;
for (int j=0; j<4; j++) { for (int j=0; j<4; j++) {
Float pos = weights[i].firstTexel + j + .5f; Float pos = weights[i].firstTexel + j + .5f;
@ -221,20 +225,26 @@ Spectrum MIPMap::getTexel(int level, int x, int y) const {
} }
Spectrum MIPMap::triangle(int level, Float x, Float y) const { Spectrum MIPMap::triangle(int level, Float x, Float y) const {
if (m_filterType == ENone) {
int xPos = floorToInt(x*m_levelWidth[0]),
yPos = floorToInt(y*m_levelHeight[0]);
return getTexel(0, xPos, yPos);
} else {
level = clamp(level, 0, m_levels - 1); level = clamp(level, 0, m_levels - 1);
x = x * m_levelWidth[level] - 0.5f; x = x * m_levelWidth[level] - 0.5f;
y = y * m_levelHeight[level] - 0.5f; y = y * m_levelHeight[level] - 0.5f;
int xPos = (int) std::floor(x), yPos = (int) std::floor(y); int xPos = floorToInt(x), yPos = floorToInt(y);
Float dx = x - xPos, dy = y - yPos; Float dx = x - xPos, dy = y - yPos;
return getTexel(level, xPos, yPos) * (1.0f - dx) * (1.0f - dy) return getTexel(level, xPos, yPos) * (1.0f - dx) * (1.0f - dy)
+ getTexel(level, xPos, yPos + 1) * (1.0f - dx) * dy + getTexel(level, xPos, yPos + 1) * (1.0f - dx) * dy
+ getTexel(level, xPos + 1, yPos) * dx * (1.0f - dy) + getTexel(level, xPos + 1, yPos) * dx * (1.0f - dy)
+ getTexel(level, xPos + 1, yPos + 1) * dx * dy; + getTexel(level, xPos + 1, yPos + 1) * dx * dy;
}
} }
Spectrum MIPMap::getValue(Float u, Float v, Spectrum MIPMap::getValue(Float u, Float v,
Float dudx, Float dudy, Float dvdx, Float dvdy) const { Float dudx, Float dudy, Float dvdx, Float dvdy) const {
if (m_isotropic) { if (m_filterType == ETrilinear) {
++mipmapLookups; ++mipmapLookups;
/* Conservatively estimate a square lookup region */ /* Conservatively estimate a square lookup region */
Float width = 2.0f * std::max( Float width = 2.0f * std::max(
@ -256,7 +266,7 @@ Spectrum MIPMap::getValue(Float u, Float v,
return triangle(level, u, v) * (1.0f - delta) return triangle(level, u, v) * (1.0f - delta)
+ triangle(level, u, v) * delta; + triangle(level, u, v) * delta;
} }
} else { } else if (m_filterType == EEWA) {
if (dudx*dudx + dudy*dudy < dvdx*dvdx + dvdy*dvdy) { if (dudx*dudx + dudy*dudy < dvdx*dvdx + dvdy*dvdy) {
std::swap(dudx, dvdx); std::swap(dudx, dvdx);
std::swap(dudy, dvdy); std::swap(dudy, dvdy);
@ -278,11 +288,15 @@ Spectrum MIPMap::getValue(Float u, Float v,
Float lod = Float lod =
std::min(std::max((Float) 0, m_levels - 1 + log2(minorLength)), std::min(std::max((Float) 0, m_levels - 1 + log2(minorLength)),
(Float) (m_levels-1)); (Float) (m_levels-1));
int ilod = (int) std::floor(lod); int ilod = floorToInt(lod);
Float d = lod - ilod; Float d = lod - ilod;
return EWA(u, v, dudx, dudy, dvdx, dvdy, ilod) * (1-d) + return EWA(u, v, dudx, dudy, dvdx, dvdy, ilod) * (1-d) +
EWA(u, v, dudx, dudy, dvdx, dvdy, ilod+1) * d; EWA(u, v, dudx, dudy, dvdx, dvdy, ilod+1) * d;
} else {
int xPos = floorToInt(u*m_levelWidth[0]),
yPos = floorToInt(v*m_levelHeight[0]);
return getTexel(0, xPos, yPos);
} }
} }

View File

@ -127,6 +127,12 @@ void Shape::serialize(Stream *stream, InstanceManager *manager) const {
stream->writeBool(m_occluder); stream->writeBool(m_occluder);
} }
Float Shape::getSurfaceArea() const {
Log(EError, "%s::getSurfaceArea(): Not implemented!",
getClass()->getName().c_str());
return 0.0f;
}
bool Shape::rayIntersect(const Ray &ray, Float mint, bool Shape::rayIntersect(const Ray &ray, Float mint,
Float maxt, Float &t, void *temp) const { Float maxt, Float &t, void *temp) const {
Log(EError, "%s::rayIntersect(): Not implemented!", Log(EError, "%s::rayIntersect(): Not implemented!",

View File

@ -29,6 +29,10 @@ Texture::Texture(Stream *stream, InstanceManager *manager)
: ConfigurableObject(stream, manager) { : ConfigurableObject(stream, manager) {
} }
Vector3i Texture::getResolution() const {
return Vector3i(0);
}
Texture::~Texture() { Texture::~Texture() {
} }

View File

@ -35,7 +35,7 @@ MTS_NAMESPACE_BEGIN
#if defined(HETVOL_STATISTICS) #if defined(HETVOL_STATISTICS)
static StatsCounter avgNewtonIterations("Heterogeneous volume", static StatsCounter avgNewtonIterations("Heterogeneous volume",
"Avg. # of Newton-Bisection iterations", EAverage); "Avg. # of Newton-Bisection iterations", EAverage);
static StatsCounter avgRayMarchingStepsTransmission("Heterogeneous volume", static StatsCounter avgRayMarchingStepsTransmittance("Heterogeneous volume",
"Avg. # of ray marching steps (transmittance)", EAverage); "Avg. # of ray marching steps (transmittance)", EAverage);
static StatsCounter avgRayMarchingStepsSampling("Heterogeneous volume", static StatsCounter avgRayMarchingStepsSampling("Heterogeneous volume",
"Avg. # of ray marching steps (sampling)", EAverage); "Avg. # of ray marching steps (sampling)", EAverage);
@ -45,7 +45,7 @@ static StatsCounter earlyExits("Heterogeneous volume",
/** /**
* Flexible heterogeneous medium implementation, which acquires its data from * Flexible heterogeneous medium implementation, which acquires its data from
* nested <tt>Volume</tt> instances. These can be constant, use a procedural * nested \ref Volume instances. These can be constant, use a procedural
* function, or fetch data from disk, e.g. using a memory-mapped density grid. * function, or fetch data from disk, e.g. using a memory-mapped density grid.
* *
* Instead of allowing separate volumes to be provided for the scattering * Instead of allowing separate volumes to be provided for the scattering
@ -53,14 +53,16 @@ static StatsCounter earlyExits("Heterogeneous volume",
* enforcing a spectrally uniform sigma_t, which must be provided using a * enforcing a spectrally uniform sigma_t, which must be provided using a
* nested scalar-valued volume named 'density'. * nested scalar-valued volume named 'density'.
* *
* A nested spectrum-valued 'albedo' volume must also be provided, which is * Another nested spectrum-valued 'albedo' volume must also be provided, which is
* used to compute the parameter sigma_s using the expression * used to compute the parameter sigma_s using the expression
* "sigma_s = density * albedo" (i.e. 'albedo' contains the single-scattering * "sigma_s = density * albedo" (i.e. 'albedo' contains the single-scattering
* albedo of the medium). * albedo of the medium).
* *
* Optionally, one can also provide an vector-valued 'orientation' volume, * Optionally, one can also provide an vector-valued 'orientation' volume,
* which contains local particle orientation that will be passed to * which contains local particle orientation that will be passed to
* scattering models such as Kajiya-Kay phase function. * scattering models such as a the Micro-flake or Kajiya-Kay phase functions.
*
* \author Wenzel Jakob
*/ */
class HeterogeneousMedium : public Medium { class HeterogeneousMedium : public Medium {
public: public:
@ -98,7 +100,7 @@ public:
Log(EError, "No density specified!"); Log(EError, "No density specified!");
if (m_albedo.get() == NULL) if (m_albedo.get() == NULL)
Log(EError, "No albedo specified!"); Log(EError, "No albedo specified!");
m_aabb = m_density->getAABB(); m_densityAABB = m_density->getAABB();
m_directionallyVaryingCoefficients = m_directionallyVaryingCoefficients =
m_phaseFunction->needsDirectionallyVaryingCoefficients(); m_phaseFunction->needsDirectionallyVaryingCoefficients();
@ -162,7 +164,7 @@ public:
/* Determine the ray segment, along which the /* Determine the ray segment, along which the
density integration should take place */ density integration should take place */
Float mint, maxt; Float mint, maxt;
if (!m_aabb.rayIntersect(ray, mint, maxt)) if (!m_densityAABB.rayIntersect(ray, mint, maxt))
return 0.0f; return 0.0f;
mint = std::max(mint, ray.mint); mint = std::max(mint, ray.mint);
@ -171,23 +173,20 @@ public:
Point p = ray(mint), pLast = ray(maxt); Point p = ray(mint), pLast = ray(maxt);
for (int i=0; i<3; ++i) {
maxComp = std::max(maxComp, std::abs(p[i]));
maxComp = std::max(maxComp, std::abs(pLast[i]));
}
/* Ignore degenerate path segments */ /* Ignore degenerate path segments */
for (int i=0; i<3; ++i)
maxComp = std::max(std::max(maxComp,
std::abs(p[i])), std::abs(pLast[i]));
if (length < 1e-6f * maxComp) if (length < 1e-6f * maxComp)
return 0.0f; return 0.0f;
/* Compute a suitable step size */ /* Compute a suitable step size */
uint32_t nSteps = (uint32_t) std::ceil(length / m_stepSize); uint32_t nSteps = (uint32_t) std::ceil(length / m_stepSize)*2;
nSteps += nSteps % 2;
const Float stepSize = length/nSteps; const Float stepSize = length/nSteps;
const Vector increment = ray.d * stepSize; const Vector increment = ray.d * stepSize;
#if defined(HETVOL_STATISTICS) #if defined(HETVOL_STATISTICS)
avgRayMarchingStepsTransmission.incrementBase(); avgRayMarchingStepsTransmittance.incrementBase();
earlyExits.incrementBase(); earlyExits.incrementBase();
#endif #endif
@ -209,7 +208,7 @@ public:
m = 6 - m; m = 6 - m;
#if defined(HETVOL_STATISTICS) #if defined(HETVOL_STATISTICS)
++avgRayMarchingStepsTransmission; ++avgRayMarchingStepsTransmittance;
#endif #endif
#if defined(HETVOL_EARLY_EXIT) #if defined(HETVOL_EARLY_EXIT)
@ -287,19 +286,17 @@ public:
/* Determine the ray segment, along which the /* Determine the ray segment, along which the
density integration should take place */ density integration should take place */
Float mint, maxt; Float mint, maxt;
if (!m_aabb.rayIntersect(ray, mint, maxt)) if (!m_densityAABB.rayIntersect(ray, mint, maxt))
return false; return false;
mint = std::max(mint, ray.mint); mint = std::max(mint, ray.mint);
maxt = std::min(maxt, ray.maxt); maxt = std::min(maxt, ray.maxt);
Float length = maxt - mint, maxComp = 0; Float length = maxt - mint, maxComp = 0;
Point p = ray(mint), pLast = ray(maxt); Point p = ray(mint), pLast = ray(maxt);
for (int i=0; i<3; ++i) {
maxComp = std::max(maxComp, std::abs(p[i]));
maxComp = std::max(maxComp, std::abs(pLast[i]));
}
/* Ignore degenerate path segments */ /* Ignore degenerate path segments */
for (int i=0; i<3; ++i)
maxComp = std::max(std::max(maxComp,
std::abs(p[i])), std::abs(pLast[i]));
if (length < 1e-6f * maxComp) if (length < 1e-6f * maxComp)
return 0.0f; return 0.0f;
@ -434,10 +431,7 @@ public:
mRec.pdfSuccessRev = expVal * densityAtMinT; mRec.pdfSuccessRev = expVal * densityAtMinT;
mRec.transmittance = Spectrum(expVal); mRec.transmittance = Spectrum(expVal);
if (mRec.pdfSuccess == 0) return success && mRec.pdfSuccess > 0;
return false;
return success;
} }
void pdfDistance(const Ray &ray, MediumSamplingRecord &mRec) const { void pdfDistance(const Ray &ray, MediumSamplingRecord &mRec) const {
@ -458,9 +452,9 @@ public:
std::string toString() const { std::string toString() const {
std::ostringstream oss; std::ostringstream oss;
oss << "HeterogeneousMedium[" << endl oss << "HeterogeneousMedium[" << endl
<< " density = " << indent(m_density.toString()) << "," << endl
<< " albedo = " << indent(m_albedo.toString()) << "," << endl << " albedo = " << indent(m_albedo.toString()) << "," << endl
<< " orientation = " << indent(m_orientation.toString()) << "," << endl << " orientation = " << indent(m_orientation.toString()) << "," << endl
<< " density = " << indent(m_density.toString()) << "," << endl
<< " stepSize = " << m_stepSize << "," << endl << " stepSize = " << m_stepSize << "," << endl
<< " densityMultiplier = " << m_densityMultiplier << endl << " densityMultiplier = " << m_densityMultiplier << endl
<< "]"; << "]";
@ -475,6 +469,11 @@ protected:
Vector orientation = m_orientation->lookupVector(p); Vector orientation = m_orientation->lookupVector(p);
if (!orientation.isZero()) if (!orientation.isZero())
density *= m_phaseFunction->sigmaDir(dot(d, orientation)); density *= m_phaseFunction->sigmaDir(dot(d, orientation));
///////// HACKY WORKAROUND FOR ZERO DENSITIES /////////
else
return 0;
///////// HACKY WORKAROUND FOR ZERO DENSITIES /////////
} }
return density; return density;
} }
@ -483,7 +482,7 @@ protected:
ref<VolumeDataSource> m_albedo; ref<VolumeDataSource> m_albedo;
ref<VolumeDataSource> m_orientation; ref<VolumeDataSource> m_orientation;
Float m_stepSize; Float m_stepSize;
AABB m_aabb; AABB m_densityAABB;
bool m_directionallyVaryingCoefficients; bool m_directionallyVaryingCoefficients;
}; };

View File

@ -16,7 +16,6 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <mitsuba/core/chisquare.h>
#include <mitsuba/core/frame.h> #include <mitsuba/core/frame.h>
#include <mitsuba/render/phase.h> #include <mitsuba/render/phase.h>
#include <mitsuba/render/medium.h> #include <mitsuba/render/medium.h>
@ -50,6 +49,8 @@ static StatsCounter avgSampleIterations("Micro-flake model",
* "Building Volumetric Appearance Models of Fabric using * "Building Volumetric Appearance Models of Fabric using
* Micro CT Imaging" by Shuang Zhao, Wenzel Jakob, Steve Marschner, * Micro CT Imaging" by Shuang Zhao, Wenzel Jakob, Steve Marschner,
* and Kavita Bala, ACM SIGGRAPH 2011 * and Kavita Bala, ACM SIGGRAPH 2011
*
* \author Wenzel Jakob
*/ */
class MicroflakePhaseFunction : public PhaseFunction { class MicroflakePhaseFunction : public PhaseFunction {
public: public:
@ -71,8 +72,14 @@ public:
} }
Float f(const PhaseFunctionQueryRecord &pRec) const { Float f(const PhaseFunctionQueryRecord &pRec) const {
if (pRec.mRec.orientation.isZero()) if (pRec.mRec.orientation.isZero()) {
/* What to do when the local orientation is undefined */
#if 0
return 1.0f / (4 * M_PI);
#else
return 0.0f; return 0.0f;
#endif
}
Frame frame(pRec.mRec.orientation); Frame frame(pRec.mRec.orientation);
Vector wi = frame.toLocal(pRec.wi); Vector wi = frame.toLocal(pRec.wi);
@ -88,8 +95,15 @@ public:
} }
inline Float sample(PhaseFunctionQueryRecord &pRec, Sampler *sampler) const { inline Float sample(PhaseFunctionQueryRecord &pRec, Sampler *sampler) const {
if (pRec.mRec.orientation.isZero()) if (pRec.mRec.orientation.isZero()) {
/* What to do when the local orientation is undefined */
#if 0
pRec.wo = squareToSphere(sampler->next2D());
return 1.0f;
#else
return 0.0f; return 0.0f;
#endif
}
Frame frame(pRec.mRec.orientation); Frame frame(pRec.mRec.orientation);
Vector wi = frame.toLocal(pRec.wi); Vector wi = frame.toLocal(pRec.wi);

View File

@ -186,6 +186,18 @@ static StatsCounter avgBrentFunEvals("Micro-flake model",
"Average Brent solver function evaluations", EAverage); "Average Brent solver function evaluations", EAverage);
#endif #endif
/**
* \brief Flake distribution for simulating rough fibers
*
* This class implements the Gaussian flake distribution proposed in
*
* "Building Volumetric Appearance Models of Fabric using
* Micro CT Imaging" by Shuang Zhao, Wenzel Jakob, Steve Marschner,
* and Kavita Bala, ACM SIGGRAPH 2011
*
* \author Wenzel Jakob
*/
class GaussianFiberDistribution { class GaussianFiberDistribution {
public: public:
inline GaussianFiberDistribution() {} inline GaussianFiberDistribution() {}

View File

@ -372,7 +372,7 @@ public:
} }
#else #else
/// Compute the AABB of a segment (only used during tree construction) /// Compute the AABB of a segment (only used during tree construction)
AABB getAABB(int index) const { AABB getAABB(index_type index) const {
index_type iv = m_segIndex.at(index); index_type iv = m_segIndex.at(index);
// cosine of steepest miter angle // cosine of steepest miter angle
@ -393,7 +393,7 @@ public:
} }
/// Compute the clipped AABB of a segment (only used during tree construction) /// Compute the clipped AABB of a segment (only used during tree construction)
AABB getClippedAABB(int index, const AABB &box) const { AABB getClippedAABB(index_type index, const AABB &box) const {
AABB aabb(getAABB(index)); AABB aabb(getAABB(index));
aabb.clip(box); aabb.clip(box);
return aabb; return aabb;

View File

@ -464,11 +464,8 @@ public:
m_meshes[i]->addChild(name, child); m_meshes[i]->addChild(name, child);
} }
} else if (cClass->derivesFrom(MTS_CLASS(Medium))) { } else if (cClass->derivesFrom(MTS_CLASS(Medium))) {
Assert(m_subsurface == NULL); for (size_t i=0; i<m_meshes.size(); ++i)
for (size_t i=0; i<m_meshes.size(); ++i) {
child->setParent(m_meshes[i]);
m_meshes[i]->addChild(name, child); m_meshes[i]->addChild(name, child);
}
} else { } else {
Shape::addChild(name, child); Shape::addChild(name, child);
} }

View File

@ -87,6 +87,14 @@ public:
return true; return true;
} }
Vector3i getResolution() const {
return Vector3i(
m_mipmap->getWidth(),
m_mipmap->getHeight(),
1
);
}
std::string toString() const { std::string toString() const {
std::ostringstream oss; std::ostringstream oss;
oss << "EXRTexture[filename=\"" << m_filename.file_string() << "\"]"; oss << "EXRTexture[filename=\"" << m_filename.file_string() << "\"]";

View File

@ -35,11 +35,6 @@ MTS_NAMESPACE_BEGIN
*/ */
class LDRTexture : public Texture2D { class LDRTexture : public Texture2D {
public: public:
enum EFilterType {
EEWAFilter = 0,
EIsotropicFilter
};
LDRTexture(const Properties &props) : Texture2D(props) { LDRTexture(const Properties &props) : Texture2D(props) {
m_filename = Thread::getThread()->getFileResolver()->resolve( m_filename = Thread::getThread()->getFileResolver()->resolve(
props.getString("filename")); props.getString("filename"));
@ -53,12 +48,14 @@ public:
std::string wrapMode = props.getString("wrapMode", "repeat"); std::string wrapMode = props.getString("wrapMode", "repeat");
if (filterType == "ewa") if (filterType == "ewa")
m_anisotropic = true; m_filterType = MIPMap::EEWA;
else if (filterType == "isotropic") else if (filterType == "trilinear")
m_anisotropic = false; m_filterType = MIPMap::ETrilinear;
else if (filterType == "none")
m_filterType = MIPMap::ENone;
else else
Log(EError, "Unknown filter type '%s' -- must be " Log(EError, "Unknown filter type '%s' -- must be "
"'ewa' or 'isotropic'!", filterType.c_str()); "'ewa', 'isotropic', or 'none'!", filterType.c_str());
if (wrapMode == "repeat") if (wrapMode == "repeat")
m_wrapMode = MIPMap::ERepeat; m_wrapMode = MIPMap::ERepeat;
@ -95,7 +92,7 @@ public:
Log(EInfo, "Unserializing texture \"%s\"", m_filename.leaf().c_str()); Log(EInfo, "Unserializing texture \"%s\"", m_filename.leaf().c_str());
m_gamma = stream->readFloat(); m_gamma = stream->readFloat();
m_format = static_cast<Bitmap::EFileFormat>(stream->readInt()); m_format = static_cast<Bitmap::EFileFormat>(stream->readInt());
m_anisotropic = stream->readBool(); m_filterType = (MIPMap::EFilterType) stream->readInt();
m_wrapMode = (MIPMap::EWrapMode) stream->readUInt(); m_wrapMode = (MIPMap::EWrapMode) stream->readUInt();
m_maxAnisotropy = stream->readFloat(); m_maxAnisotropy = stream->readFloat();
uint32_t size = stream->readUInt(); uint32_t size = stream->readUInt();
@ -204,7 +201,7 @@ public:
Log(EError, "%i bpp images are currently not supported!", bitmap->getBitsPerPixel()); Log(EError, "%i bpp images are currently not supported!", bitmap->getBitsPerPixel());
} }
m_mipmap = MIPMap::fromBitmap(corrected, !m_anisotropic, m_mipmap = MIPMap::fromBitmap(corrected, m_filterType,
m_wrapMode, m_maxAnisotropy); m_wrapMode, m_maxAnisotropy);
m_average = m_mipmap->triangle(m_mipmap->getLevels()-1, 0, 0); m_average = m_mipmap->triangle(m_mipmap->getLevels()-1, 0, 0);
m_maximum = m_mipmap->getMaximum(); m_maximum = m_mipmap->getMaximum();
@ -215,7 +212,7 @@ public:
stream->writeString(m_filename.file_string()); stream->writeString(m_filename.file_string());
stream->writeFloat(m_gamma); stream->writeFloat(m_gamma);
stream->writeInt(m_format); stream->writeInt(m_format);
stream->writeBool(m_anisotropic); stream->writeInt(m_filterType);
stream->writeUInt(m_wrapMode); stream->writeUInt(m_wrapMode);
stream->writeFloat(m_maxAnisotropy); stream->writeFloat(m_maxAnisotropy);
@ -251,6 +248,14 @@ public:
return true; return true;
} }
Vector3i getResolution() const {
return Vector3i(
m_mipmap->getWidth(),
m_mipmap->getHeight(),
1
);
}
std::string toString() const { std::string toString() const {
std::ostringstream oss; std::ostringstream oss;
oss << "LDRTexture[" << endl oss << "LDRTexture[" << endl
@ -268,9 +273,9 @@ protected:
ref<MemoryStream> m_stream; ref<MemoryStream> m_stream;
fs::path m_filename; fs::path m_filename;
Bitmap::EFileFormat m_format; Bitmap::EFileFormat m_format;
MIPMap::EFilterType m_filterType;
Spectrum m_average, m_maximum; Spectrum m_average, m_maximum;
Float m_gamma; Float m_gamma;
bool m_anisotropic;
MIPMap::EWrapMode m_wrapMode; MIPMap::EWrapMode m_wrapMode;
Float m_maxAnisotropy; Float m_maxAnisotropy;
}; };
@ -340,7 +345,8 @@ private:
Shader *LDRTexture::createShader(Renderer *renderer) const { Shader *LDRTexture::createShader(Renderer *renderer) const {
return new LDRTextureShader(renderer, m_filename.leaf(), return new LDRTextureShader(renderer, m_filename.leaf(),
m_mipmap->getLDRBitmap(), m_uvOffset, m_uvScale, m_mipmap->getLDRBitmap(), m_uvOffset, m_uvScale,
m_wrapMode, m_anisotropic ? m_maxAnisotropy : 1.0f); m_wrapMode, (m_filterType == MIPMap::EEWA)
? m_maxAnisotropy : 1.0f);
} }
MTS_IMPLEMENT_CLASS_S(LDRTexture, false, Texture2D) MTS_IMPLEMENT_CLASS_S(LDRTexture, false, Texture2D)