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