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();
/**
* \brief Construct a random generator with a custom seed
*/
Random(uint64_t seed);
/// Construct a new random generator seeded from a pre-existing one
Random(Random *random);

View File

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

View File

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

View File

@ -195,8 +195,12 @@ public:
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
virtual AABB getAABB() const = 0;

View File

@ -39,6 +39,9 @@ public:
/// Return the component-wise maximum of the texture over its domain
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
* differentials are available?
@ -64,11 +67,6 @@ public:
/// Serialize to a binary data stream
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
virtual Spectrum getValue(const Point2 &uv) const = 0;
@ -76,6 +74,11 @@ protected:
virtual Spectrum getValue(const Point2 &uv, Float dudx,
Float dudy, Float dvdx, Float dvdy) const = 0;
MTS_DECLARE_CLASS()
protected:
Texture2D(const Properties &props);
Texture2D(Stream *stream, InstanceManager *manager);
virtual ~Texture2D();
protected:
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/composite', ['composite.cpp'])
plugins += env.SharedLibrary('#plugins/twosided', ['twosided.cpp'])
plugins += env.SharedLibrary('#plugins/irawan', ['irawan.cpp'])
Export('plugins')

View File

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

View File

@ -80,6 +80,11 @@ Random::Random(Random *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)
: SerializableObject(stream, manager) {
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 */
MIPMap::MIPMap(int width, int height, Spectrum *pixels,
bool isotropic, EWrapMode wrapMode, Float maxAnisotropy)
: m_width(width), m_height(height), m_isotropic(isotropic),
EFilterType filterType, EWrapMode wrapMode, Float maxAnisotropy)
: m_width(width), m_height(height), m_filterType(filterType),
m_wrapMode(wrapMode), m_maxAnisotropy(maxAnisotropy) {
Spectrum *texture = pixels;
if (!isPow2(width) || !isPow2(height)) {
if (filterType != ENone && (!isPow2(width) || !isPow2(height))) {
m_width = (int) roundToPow2((uint32_t) width);
m_height = (int) roundToPow2((uint32_t) height);
@ -87,7 +87,11 @@ MIPMap::MIPMap(int width, int height, Spectrum *pixels,
delete[] texture1;
}
if (m_filterType != ENone)
m_levels = 1 + log2i((uint32_t) std::max(width, height));
else
m_levels = 1;
m_pyramid = new Spectrum*[m_levels];
m_pyramid[0] = texture;
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));
for (int i=0; i<MIPMAP_LUTSIZE; ++i) {
Float pos = (Float) i / (Float) (MIPMAP_LUTSIZE-1);
@ -121,7 +125,7 @@ MIPMap::MIPMap(int width, int height, Spectrum *pixels,
}
MIPMap::~MIPMap() {
if (!m_isotropic)
if (m_filterType == EEWA)
freeAligned(m_weightLut);
for (int i=0; i<m_levels; i++)
delete[] m_pyramid[i];
@ -149,7 +153,7 @@ Spectrum MIPMap::getMaximum() const {
return max;
}
ref<MIPMap> MIPMap::fromBitmap(Bitmap *bitmap, bool isotropic,
ref<MIPMap> MIPMap::fromBitmap(Bitmap *bitmap, EFilterType filterType,
EWrapMode wrapMode, Float maxAnisotropy) {
int width = bitmap->getWidth();
int height = bitmap->getHeight();
@ -169,7 +173,7 @@ ref<MIPMap> MIPMap::fromBitmap(Bitmap *bitmap, bool isotropic,
}
return new MIPMap(width, height, pixels,
isotropic, wrapMode, maxAnisotropy);
filterType, wrapMode, maxAnisotropy);
}
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];
for (int i=0; i<newRes; i++) {
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;
for (int j=0; j<4; j++) {
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 {
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);
x = x * m_levelWidth[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;
return getTexel(level, xPos, yPos) * (1.0f - dx) * (1.0f - dy)
+ getTexel(level, xPos, yPos + 1) * (1.0f - dx) * dy
+ getTexel(level, xPos + 1, yPos) * dx * (1.0f - dy)
+ getTexel(level, xPos + 1, yPos + 1) * dx * dy;
}
}
Spectrum MIPMap::getValue(Float u, Float v,
Float dudx, Float dudy, Float dvdx, Float dvdy) const {
if (m_isotropic) {
if (m_filterType == ETrilinear) {
++mipmapLookups;
/* Conservatively estimate a square lookup region */
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)
+ triangle(level, u, v) * delta;
}
} else {
} else if (m_filterType == EEWA) {
if (dudx*dudx + dudy*dudy < dvdx*dvdx + dvdy*dvdy) {
std::swap(dudx, dvdx);
std::swap(dudy, dvdy);
@ -278,11 +288,15 @@ Spectrum MIPMap::getValue(Float u, Float v,
Float lod =
std::min(std::max((Float) 0, m_levels - 1 + log2(minorLength)),
(Float) (m_levels-1));
int ilod = (int) std::floor(lod);
int ilod = floorToInt(lod);
Float d = lod - ilod;
return 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);
}
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,
Float maxt, Float &t, void *temp) const {
Log(EError, "%s::rayIntersect(): Not implemented!",

View File

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

View File

@ -35,7 +35,7 @@ MTS_NAMESPACE_BEGIN
#if defined(HETVOL_STATISTICS)
static StatsCounter avgNewtonIterations("Heterogeneous volume",
"Avg. # of Newton-Bisection iterations", EAverage);
static StatsCounter avgRayMarchingStepsTransmission("Heterogeneous volume",
static StatsCounter avgRayMarchingStepsTransmittance("Heterogeneous volume",
"Avg. # of ray marching steps (transmittance)", EAverage);
static StatsCounter avgRayMarchingStepsSampling("Heterogeneous volume",
"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
* 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.
*
* 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
* 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
* "sigma_s = density * albedo" (i.e. 'albedo' contains the single-scattering
* albedo of the medium).
*
* Optionally, one can also provide an vector-valued 'orientation' volume,
* 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 {
public:
@ -98,7 +100,7 @@ public:
Log(EError, "No density specified!");
if (m_albedo.get() == NULL)
Log(EError, "No albedo specified!");
m_aabb = m_density->getAABB();
m_densityAABB = m_density->getAABB();
m_directionallyVaryingCoefficients =
m_phaseFunction->needsDirectionallyVaryingCoefficients();
@ -162,7 +164,7 @@ public:
/* Determine the ray segment, along which the
density integration should take place */
Float mint, maxt;
if (!m_aabb.rayIntersect(ray, mint, maxt))
if (!m_densityAABB.rayIntersect(ray, mint, maxt))
return 0.0f;
mint = std::max(mint, ray.mint);
@ -171,23 +173,20 @@ public:
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 */
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)
return 0.0f;
/* Compute a suitable step size */
uint32_t nSteps = (uint32_t) std::ceil(length / m_stepSize);
nSteps += nSteps % 2;
uint32_t nSteps = (uint32_t) std::ceil(length / m_stepSize)*2;
const Float stepSize = length/nSteps;
const Vector increment = ray.d * stepSize;
#if defined(HETVOL_STATISTICS)
avgRayMarchingStepsTransmission.incrementBase();
avgRayMarchingStepsTransmittance.incrementBase();
earlyExits.incrementBase();
#endif
@ -209,7 +208,7 @@ public:
m = 6 - m;
#if defined(HETVOL_STATISTICS)
++avgRayMarchingStepsTransmission;
++avgRayMarchingStepsTransmittance;
#endif
#if defined(HETVOL_EARLY_EXIT)
@ -287,19 +286,17 @@ public:
/* Determine the ray segment, along which the
density integration should take place */
Float mint, maxt;
if (!m_aabb.rayIntersect(ray, mint, maxt))
if (!m_densityAABB.rayIntersect(ray, mint, maxt))
return false;
mint = std::max(mint, ray.mint);
maxt = std::min(maxt, ray.maxt);
Float length = maxt - mint, maxComp = 0;
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 */
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)
return 0.0f;
@ -434,10 +431,7 @@ public:
mRec.pdfSuccessRev = expVal * densityAtMinT;
mRec.transmittance = Spectrum(expVal);
if (mRec.pdfSuccess == 0)
return false;
return success;
return success && mRec.pdfSuccess > 0;
}
void pdfDistance(const Ray &ray, MediumSamplingRecord &mRec) const {
@ -458,9 +452,9 @@ public:
std::string toString() const {
std::ostringstream oss;
oss << "HeterogeneousMedium[" << endl
<< " density = " << indent(m_density.toString()) << "," << endl
<< " albedo = " << indent(m_albedo.toString()) << "," << endl
<< " orientation = " << indent(m_orientation.toString()) << "," << endl
<< " density = " << indent(m_density.toString()) << "," << endl
<< " stepSize = " << m_stepSize << "," << endl
<< " densityMultiplier = " << m_densityMultiplier << endl
<< "]";
@ -475,6 +469,11 @@ protected:
Vector orientation = m_orientation->lookupVector(p);
if (!orientation.isZero())
density *= m_phaseFunction->sigmaDir(dot(d, orientation));
///////// HACKY WORKAROUND FOR ZERO DENSITIES /////////
else
return 0;
///////// HACKY WORKAROUND FOR ZERO DENSITIES /////////
}
return density;
}
@ -483,7 +482,7 @@ protected:
ref<VolumeDataSource> m_albedo;
ref<VolumeDataSource> m_orientation;
Float m_stepSize;
AABB m_aabb;
AABB m_densityAABB;
bool m_directionallyVaryingCoefficients;
};

View File

@ -16,7 +16,6 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <mitsuba/core/chisquare.h>
#include <mitsuba/core/frame.h>
#include <mitsuba/render/phase.h>
#include <mitsuba/render/medium.h>
@ -50,6 +49,8 @@ static StatsCounter avgSampleIterations("Micro-flake model",
* "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 MicroflakePhaseFunction : public PhaseFunction {
public:
@ -71,8 +72,14 @@ public:
}
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;
#endif
}
Frame frame(pRec.mRec.orientation);
Vector wi = frame.toLocal(pRec.wi);
@ -88,8 +95,15 @@ public:
}
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;
#endif
}
Frame frame(pRec.mRec.orientation);
Vector wi = frame.toLocal(pRec.wi);

View File

@ -186,6 +186,18 @@ static StatsCounter avgBrentFunEvals("Micro-flake model",
"Average Brent solver function evaluations", EAverage);
#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 {
public:
inline GaussianFiberDistribution() {}

View File

@ -372,7 +372,7 @@ public:
}
#else
/// 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);
// cosine of steepest miter angle
@ -393,7 +393,7 @@ public:
}
/// 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.clip(box);
return aabb;

View File

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

View File

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

View File

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