BSDF::getFrame/BSDF::getFrameDerivative functions, Shape::adjustTime() feature
parent
27a17f3bf7
commit
eae7a55eac
|
@ -26,6 +26,7 @@
|
|||
#define EIGEN_NO_DEBUG
|
||||
|
||||
#include <Eigen/Core>
|
||||
#include <Eigen/Geometry>
|
||||
#include <cmath>
|
||||
#include <stdexcept>
|
||||
|
||||
|
|
|
@ -336,6 +336,11 @@ public:
|
|||
/// Return the diffuse reflectance value (if any)
|
||||
virtual Spectrum getDiffuseReflectance(const Intersection &its) const;
|
||||
|
||||
/// Return the specular reflectance value (if any)
|
||||
virtual Spectrum getSpecularReflectance(const Intersection &its) const {
|
||||
return Spectrum(0.0f);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Sample the BSDF and return the importance weight (i.e. the
|
||||
* value of the BSDF divided by the probability density of the sample).
|
||||
|
@ -462,6 +467,15 @@ public:
|
|||
*/
|
||||
virtual Frame getFrame(const Intersection &its) const;
|
||||
|
||||
/**
|
||||
* \brief Sometimes, BSDF models make use of a perturbed frame for
|
||||
* internal shading computations (e.g. bump maps). This function
|
||||
* computes the derivative of this frame with respect to the UV
|
||||
* parameterization of the underlying shape.
|
||||
*/
|
||||
virtual void getFrameDerivative(const Intersection &its,
|
||||
Frame &du, Frame &dv) const;
|
||||
|
||||
// =============================================================
|
||||
//! @{ \name ConfigurableObject interface
|
||||
// =============================================================
|
||||
|
|
|
@ -92,6 +92,24 @@ inline const Medium *Intersection::getTargetMedium(Float cosTheta) const {
|
|||
return shape->getInteriorMedium();
|
||||
}
|
||||
|
||||
void Intersection::adjustTime(Float time) {
|
||||
if (instance)
|
||||
instance->adjustTime(*this, time);
|
||||
else if (shape)
|
||||
shape->adjustTime(*this, time);
|
||||
else
|
||||
this->time = time;
|
||||
}
|
||||
|
||||
void Intersection::getNormalDerivative(Vector &dndu, Vector &dndv,
|
||||
bool shadingFrame) const {
|
||||
|
||||
if (instance)
|
||||
instance->getNormalDerivative(*this, dndu, dndv, shadingFrame);
|
||||
else if (shape)
|
||||
shape->getNormalDerivative(*this, dndu, dndv, shadingFrame);
|
||||
}
|
||||
|
||||
inline const PhaseFunction *MediumSamplingRecord::getPhaseFunction() const {
|
||||
return medium->getPhaseFunction();
|
||||
}
|
||||
|
|
|
@ -118,6 +118,13 @@ public:
|
|||
/// Computes texture coordinate partials
|
||||
void computePartials(const RayDifferential &ray);
|
||||
|
||||
/// Move the intersection forward or backward through time
|
||||
inline void adjustTime(Float time);
|
||||
|
||||
/// Calls the suitable implementaiton of \ref Shape::getNormalDerivative()
|
||||
inline void getNormalDerivative(Vector &dndu, Vector &dndv,
|
||||
bool shadingFrame = true) const;
|
||||
|
||||
/// Return a string representation
|
||||
std::string toString() const;
|
||||
public:
|
||||
|
@ -316,6 +323,11 @@ public:
|
|||
void getCurvature(const Intersection &its, Float &H, Float &K,
|
||||
bool shadingFrame = true) const;
|
||||
|
||||
/**
|
||||
* Adjust an intersection record to a different time value
|
||||
*/
|
||||
virtual void adjustTime(Intersection &its, Float time) const;
|
||||
|
||||
/**
|
||||
* \brief Return the internal kd-tree of this shape (if any)
|
||||
*
|
||||
|
|
|
@ -80,12 +80,13 @@ public:
|
|||
TriMesh(Stream *stream, InstanceManager *manager);
|
||||
|
||||
/**
|
||||
* Unserialize a triangle mesh - this is an alternative
|
||||
* routine, which only loads triangle data (no BSDF,
|
||||
* Sub-surface integrator, etc.) in a format that
|
||||
* will remain stable as Mitsuba evolves. The files
|
||||
* can optionally contain multiple meshes -- in that case,
|
||||
* the specified index determines which one to load.
|
||||
* \brief Unserialize a triangle mesh
|
||||
*
|
||||
* This is an alternative routine, which only loads triangle data
|
||||
* (no BSDF, Sub-surface integrator, etc.) in a format that will
|
||||
* remain stable as Mitsuba evolves. The files can optionally contain
|
||||
* multiple meshes -- in that case, the specified index determines
|
||||
* which one to load.
|
||||
*/
|
||||
TriMesh(Stream *stream, int idx = 0);
|
||||
|
||||
|
|
|
@ -105,6 +105,14 @@ public:
|
|||
manager->serialize(stream, m_displacement.get());
|
||||
}
|
||||
|
||||
Spectrum getDiffuseReflectance(const Intersection &its) const {
|
||||
return m_nested->getDiffuseReflectance(its);
|
||||
}
|
||||
|
||||
Spectrum getSpecularReflectance(const Intersection &its) const {
|
||||
return m_nested->getSpecularReflectance(its);
|
||||
}
|
||||
|
||||
void addChild(const std::string &name, ConfigurableObject *child) {
|
||||
if (child->getClass()->derivesFrom(MTS_CLASS(BSDF))) {
|
||||
if (m_nested != NULL)
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
MTS_NAMESPACE_BEGIN
|
||||
|
||||
/*!\plugin{mask}{Opacity mask}
|
||||
* \order{18}
|
||||
* \order{19}
|
||||
* \parameters{
|
||||
* \parameter{opacity}{\Spectrum\Or\Texture}{
|
||||
* Specifies the per-channel opacity (where $1=$ completely opaque)\default{0.5}.
|
||||
|
|
|
@ -77,6 +77,14 @@ public:
|
|||
manager->serialize(stream, m_normals.get());
|
||||
}
|
||||
|
||||
Spectrum getDiffuseReflectance(const Intersection &its) const {
|
||||
return m_nested->getDiffuseReflectance(its);
|
||||
}
|
||||
|
||||
Spectrum getSpecularReflectance(const Intersection &its) const {
|
||||
return m_nested->getSpecularReflectance(its);
|
||||
}
|
||||
|
||||
void addChild(const std::string &name, ConfigurableObject *child) {
|
||||
if (child->getClass()->derivesFrom(MTS_CLASS(BSDF))) {
|
||||
if (m_nested != NULL)
|
||||
|
@ -97,23 +105,65 @@ public:
|
|||
}
|
||||
|
||||
Frame getFrame(const Intersection &its) const {
|
||||
Frame result;
|
||||
Normal n;
|
||||
|
||||
m_normals->eval(its, false).toLinearRGB(n.x, n.y, n.z);
|
||||
for (int i=0; i<3; ++i)
|
||||
n[i] = 2 * n[i] - 1;
|
||||
|
||||
Frame result;
|
||||
result.n = normalize(its.shFrame.toWorld(n));
|
||||
Frame frame = BSDF::getFrame(its);
|
||||
result.n = normalize(frame.toWorld(n));
|
||||
|
||||
result.s = normalize(its.dpdu - result.n
|
||||
* dot(result.n, its.dpdu));
|
||||
|
||||
result.t = cross(result.n, result.s);
|
||||
|
||||
if (dot(result.n, its.geoFrame.n) < 0)
|
||||
result.n *= -1;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void getFrameDerivative(const Intersection &its, Frame &du, Frame &dv) const {
|
||||
Vector n;
|
||||
|
||||
m_normals->eval(its, false).toLinearRGB(n.x, n.y, n.z);
|
||||
for (int i=0; i<3; ++i)
|
||||
n[i] = 2 * n[i] - 1;
|
||||
|
||||
Spectrum dn[2];
|
||||
Vector dndu, dndv;
|
||||
m_normals->evalGradient(its, dn);
|
||||
Spectrum(2*dn[0]).toLinearRGB(dndu.x, dndu.y, dndu.z);
|
||||
Spectrum(2*dn[1]).toLinearRGB(dndv.x, dndv.y, dndv.z);
|
||||
|
||||
Frame base_du, base_dv;
|
||||
Frame base = BSDF::getFrame(its);
|
||||
BSDF::getFrameDerivative(its, base_du, base_dv);
|
||||
|
||||
Vector worldN = base.toWorld(n);
|
||||
|
||||
Float invLength_n = 1/worldN.length();
|
||||
worldN *= invLength_n;
|
||||
|
||||
du.n = invLength_n * (base.toWorld(dndu) + base_du.toWorld(n));
|
||||
dv.n = invLength_n * (base.toWorld(dndv) + base_dv.toWorld(n));
|
||||
du.n -= dot(du.n, worldN) * worldN;
|
||||
dv.n -= dot(dv.n, worldN) * worldN;
|
||||
|
||||
Vector s = its.dpdu - worldN * dot(worldN, its.dpdu);
|
||||
Float invLen_s = 1.0f / s.length();
|
||||
s *= invLen_s;
|
||||
|
||||
du.s = invLen_s * (-du.n * dot(worldN, its.dpdu) - worldN * dot(du.n, its.dpdu));
|
||||
dv.s = invLen_s * (-dv.n * dot(worldN, its.dpdu) - worldN * dot(dv.n, its.dpdu));
|
||||
|
||||
du.s -= s * dot(du.s, s);
|
||||
dv.s -= s * dot(dv.s, s);
|
||||
|
||||
du.t = cross(du.n, s) + cross(worldN, du.s);
|
||||
dv.t = cross(dv.n, s) + cross(worldN, dv.s);
|
||||
}
|
||||
|
||||
Spectrum eval(const BSDFSamplingRecord &bRec, EMeasure measure) const {
|
||||
const Intersection& its = bRec.its;
|
||||
Intersection perturbed(its);
|
||||
|
@ -283,5 +333,5 @@ Shader *NormalMap::createShader(Renderer *renderer) const {
|
|||
|
||||
MTS_IMPLEMENT_CLASS(NormalMapShader, false, Shader)
|
||||
MTS_IMPLEMENT_CLASS_S(NormalMap, false, BSDF)
|
||||
MTS_EXPORT_PLUGIN(NormalMap, "Smooth dielectric coating");
|
||||
MTS_EXPORT_PLUGIN(NormalMap, "Normal map modifier");
|
||||
MTS_NAMESPACE_END
|
||||
|
|
|
@ -110,6 +110,10 @@ public:
|
|||
return m_diffuseReflectance->eval(its);
|
||||
}
|
||||
|
||||
Spectrum getSpecularReflectance(const Intersection &its) const {
|
||||
return m_specularReflectance->eval(its);
|
||||
}
|
||||
|
||||
/// Reflection in local coordinates
|
||||
inline Vector reflect(const Vector &wi) const {
|
||||
return Vector(-wi.x, -wi.y, wi.z);
|
||||
|
|
|
@ -220,6 +220,9 @@ public:
|
|||
return m_diffuseReflectance->eval(its) * (1-m_fdrExt);
|
||||
}
|
||||
|
||||
Spectrum getSpecularReflectance(const Intersection &its) const {
|
||||
return m_specularReflectance->eval(its);
|
||||
}
|
||||
|
||||
void addChild(const std::string &name, ConfigurableObject *child) {
|
||||
if (child->getClass()->derivesFrom(MTS_CLASS(Texture))) {
|
||||
|
|
|
@ -311,6 +311,10 @@ public:
|
|||
return m_diffuseReflectance->eval(its) * Ftr;
|
||||
}
|
||||
|
||||
Spectrum getSpecularReflectance(const Intersection &its) const {
|
||||
return m_specularReflectance->eval(its);
|
||||
}
|
||||
|
||||
/// Helper function: reflect \c wi with respect to a given surface normal
|
||||
inline Vector reflect(const Vector &wi, const Normal &m) const {
|
||||
return 2 * dot(wi, m) * Vector(m) - wi;
|
||||
|
|
|
@ -64,7 +64,32 @@ Float BSDF::getEta() const {
|
|||
}
|
||||
|
||||
Frame BSDF::getFrame(const Intersection &its) const {
|
||||
return its.shFrame;
|
||||
Frame result;
|
||||
|
||||
result.n = its.shFrame.n;
|
||||
result.s = normalize(its.dpdu - result.n
|
||||
* dot(result.n, its.dpdu));
|
||||
result.t = cross(result.n, result.s);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void BSDF::getFrameDerivative(const Intersection &its, Frame &du, Frame &dv) const {
|
||||
(its.instance ? its.instance : its.shape)->getNormalDerivative(its, du.n, dv.n, true);
|
||||
|
||||
Vector n = its.shFrame.n;
|
||||
Vector s = its.dpdu - n * dot(n, its.dpdu);
|
||||
Float invLen_s = 1.0f / s.length();
|
||||
s *= invLen_s;
|
||||
|
||||
du.s = invLen_s * (-du.n * dot(n, its.dpdu) - n * dot(du.n, its.dpdu));
|
||||
dv.s = invLen_s * (-dv.n * dot(n, its.dpdu) - n * dot(dv.n, its.dpdu));
|
||||
|
||||
du.s -= s * dot(du.s, s);
|
||||
dv.s -= s * dot(dv.s, s);
|
||||
|
||||
du.t = cross(du.n, s) + cross(n, du.s);
|
||||
dv.t = cross(dv.n, s) + cross(n, dv.s);
|
||||
}
|
||||
|
||||
Float BSDF::getRoughness(const Intersection &its, int component) const {
|
||||
|
|
|
@ -73,6 +73,11 @@ void Shape::configure() {
|
|||
"emitter/sensor/subsurface attachment. This is not allowed!", getName().c_str());
|
||||
}
|
||||
|
||||
void Shape::adjustTime(Intersection &its, Float time) const {
|
||||
its.time = time;
|
||||
/* Do nothing else by default */
|
||||
}
|
||||
|
||||
bool Shape::isCompound() const {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -129,6 +129,24 @@ bool Instance::rayIntersect(const Ray &_ray, Float mint, Float maxt) const {
|
|||
return kdtree->rayIntersect(ray, mint, maxt);
|
||||
}
|
||||
|
||||
void Instance::adjustTime(Intersection &its, Float time) const {
|
||||
Transform trafo = m_transform->eval(its.time).inverse();
|
||||
trafo = m_transform->eval(time) * trafo;
|
||||
|
||||
Vector s = trafo(its.shFrame.s);
|
||||
its.shFrame.n = normalize(trafo(its.shFrame.n));
|
||||
its.shFrame.s = normalize(s - its.shFrame.n
|
||||
* dot(its.shFrame.n, s));
|
||||
its.shFrame.t = cross(its.shFrame.n, its.shFrame.s);
|
||||
its.geoFrame = Frame(normalize(trafo(its.geoFrame.n)));
|
||||
its.dpdu = trafo(its.dpdu);
|
||||
its.dpdv = trafo(its.dpdv);
|
||||
its.p = trafo(its.p);
|
||||
its.wi = normalize(trafo(its.wi));
|
||||
its.instance = this;
|
||||
its.time = time;
|
||||
}
|
||||
|
||||
void Instance::fillIntersectionRecord(const Ray &_ray,
|
||||
const void *temp, Intersection &its) const {
|
||||
const ShapeKDTree *kdtree = m_shapeGroup->getKDTree();
|
||||
|
|
|
@ -51,6 +51,9 @@ public:
|
|||
/// Return a pointer to the associated \ref ShapeGroup (const version)
|
||||
inline const ShapeGroup* getShapeGroup() const { return m_shapeGroup.get(); }
|
||||
|
||||
/// Return the underlying animated transformation
|
||||
inline const AnimatedTransform *getAnimatedTransform() const { return m_transform.get(); }
|
||||
|
||||
// =============================================================
|
||||
//! @{ \name Implementation of the Shape interface
|
||||
// =============================================================
|
||||
|
@ -72,6 +75,8 @@ public:
|
|||
|
||||
size_t getEffectivePrimitiveCount() const;
|
||||
|
||||
void adjustTime(Intersection &its, Float time) const;
|
||||
|
||||
//! @}
|
||||
// =============================================================
|
||||
|
||||
|
|
Loading…
Reference in New Issue