535 lines
17 KiB
C++
535 lines
17 KiB
C++
/*
|
|
This file is part of Mitsuba, a physically based rendering system.
|
|
|
|
Copyright (c) 2007-2014 by Wenzel Jakob and others.
|
|
|
|
Mitsuba is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License Version 3
|
|
as published by the Free Software Foundation.
|
|
|
|
Mitsuba is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#pragma once
|
|
#if !defined(__MITSUBA_RENDER_SHAPE_H_)
|
|
#define __MITSUBA_RENDER_SHAPE_H_
|
|
|
|
#include <mitsuba/render/common.h>
|
|
#include <mitsuba/core/cobject.h>
|
|
#include <mitsuba/core/transform.h>
|
|
#include <mitsuba/core/frame.h>
|
|
#include <mitsuba/core/aabb.h>
|
|
|
|
MTS_NAMESPACE_BEGIN
|
|
|
|
/** \brief Container for all information related to
|
|
* a surface intersection
|
|
* \ingroup librender
|
|
* \ingroup libpython
|
|
*/
|
|
struct MTS_EXPORT_RENDER Intersection {
|
|
public:
|
|
inline Intersection() :
|
|
shape(NULL), t(std::numeric_limits<Float>::infinity()) { }
|
|
|
|
/// Convert a local shading-space vector into world space
|
|
inline Vector toWorld(const Vector &v) const {
|
|
return shFrame.toWorld(v);
|
|
}
|
|
|
|
/// Convert a world-space vector into local shading coordinates
|
|
inline Vector toLocal(const Vector &v) const {
|
|
return shFrame.toLocal(v);
|
|
}
|
|
|
|
/// Is the current intersection valid?
|
|
inline bool isValid() const {
|
|
return t != std::numeric_limits<Float>::infinity();
|
|
}
|
|
|
|
/// Is the intersected shape also a emitter?
|
|
inline bool isEmitter() const;
|
|
|
|
/// Is the intersected shape also a sensor?
|
|
inline bool isSensor() const;
|
|
|
|
/// Does the intersected shape have a subsurface integrator?
|
|
inline bool hasSubsurface() const;
|
|
|
|
/// Does the surface mark a transition between two media?
|
|
inline bool isMediumTransition() const;
|
|
|
|
/**
|
|
* \brief Determine the target medium
|
|
*
|
|
* When \c isMediumTransition() = \c true, determine the medium that
|
|
* contains the ray (\c this->p, \c d)
|
|
*/
|
|
inline const Medium *getTargetMedium(const Vector &d) const;
|
|
|
|
/**
|
|
* \brief Determine the target medium based on the cosine
|
|
* of the angle between the geometric normal and a direction
|
|
*
|
|
* Returns the exterior medium when \c cosTheta > 0 and
|
|
* the interior medium when \c cosTheta <= 0.
|
|
*/
|
|
inline const Medium *getTargetMedium(Float cosTheta) const;
|
|
|
|
/**
|
|
* \brief Returns the BSDF of the intersected shape.
|
|
*
|
|
* The parameter ray must match the one used to create the intersection
|
|
* record. This function computes texture coordinate partials if this is
|
|
* required by the BSDF (e.g. for texture filtering).
|
|
*
|
|
* \remark This function should only be called if there is a valid
|
|
* intersection!
|
|
*/
|
|
inline const BSDF *getBSDF(const RayDifferential &ray);
|
|
|
|
/// Returns the BSDF of the intersected shape
|
|
inline const BSDF *getBSDF() const;
|
|
|
|
/**
|
|
* \brief Returns radiance emitted into direction d.
|
|
*
|
|
* \remark This function should only be called if the
|
|
* intersected shape is actually an emitter.
|
|
*/
|
|
inline Spectrum Le(const Vector &d) const;
|
|
|
|
/**
|
|
* \brief Returns radiance from a subsurface integrator
|
|
* emitted into direction d.
|
|
*
|
|
* \remark Should only be called if the intersected
|
|
* shape is actually a subsurface integrator.
|
|
*/
|
|
inline Spectrum LoSub(const Scene *scene, Sampler *sampler,
|
|
const Vector &d, int depth=0) const;
|
|
|
|
/// 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 implementation of \ref Shape::getNormalDerivative()
|
|
inline void getNormalDerivative(Vector &dndu, Vector &dndv,
|
|
bool shadingFrame = true) const;
|
|
|
|
/// Return a string representation
|
|
std::string toString() const;
|
|
public:
|
|
/// Pointer to the associated shape
|
|
const Shape *shape;
|
|
|
|
/// Distance traveled along the ray
|
|
Float t;
|
|
|
|
/* Intersection point in 3D coordinates */
|
|
Point p;
|
|
|
|
/// Geometry frame
|
|
Frame geoFrame;
|
|
|
|
/// Shading frame
|
|
Frame shFrame;
|
|
|
|
/// UV surface coordinates
|
|
Point2 uv;
|
|
|
|
/// Position partials wrt. the UV parameterization
|
|
Vector dpdu, dpdv;
|
|
|
|
/// UV partials wrt. changes in screen-space
|
|
Float dudx, dudy, dvdx, dvdy;
|
|
|
|
/// Time value associated with the intersection
|
|
Float time;
|
|
|
|
/// Interpolated vertex color
|
|
Spectrum color;
|
|
|
|
/// Incident direction in the local shading frame
|
|
Vector wi;
|
|
|
|
/// Have texture coordinate partials been computed
|
|
bool hasUVPartials : 1;
|
|
|
|
/// Primitive index, e.g. the triangle ID (if applicable)
|
|
uint32_t primIndex : 31;
|
|
|
|
/// Stores a pointer to the parent instance, if applicable
|
|
const Shape *instance;
|
|
};
|
|
|
|
/** \brief Abstract base class of all shapes
|
|
* \ingroup librender
|
|
* \ingroup libpython
|
|
*/
|
|
class MTS_EXPORT_RENDER Shape : public ConfigurableObject {
|
|
public:
|
|
// =============================================================
|
|
//! @{ \name Query functions to be implemented in subclasses
|
|
// =============================================================
|
|
|
|
/// Return the name of this shape (e.g. the filename)
|
|
virtual std::string getName() const;
|
|
|
|
/// Is this a compound shape consisting of several sub-objects?
|
|
virtual bool isCompound() const;
|
|
|
|
/**
|
|
* \brief Return a sub-element of a compound shape.
|
|
*
|
|
* When expanding shapes, the scene will repeatedly call this
|
|
* function with increasing indices. Returning \a NULL indicates
|
|
* that no more elements are available.
|
|
*/
|
|
virtual Shape *getElement(int i);
|
|
|
|
/**
|
|
* \brief Return the shape's surface area
|
|
*
|
|
* Assumes that the object is not undergoing some kind of
|
|
* time-dependent scaling.
|
|
*
|
|
* The default implementation throws an exception
|
|
*/
|
|
virtual Float getSurfaceArea() const;
|
|
|
|
/// Return a bounding box containing the shape
|
|
virtual AABB getAABB() const = 0;
|
|
|
|
/**
|
|
* \brief Returns the minimal axis-aligned bounding box
|
|
* of this shape when clipped to another bounding box.
|
|
*
|
|
* This is extremely important to construct decent kd-trees.
|
|
* The default implementation just takes the bounding box
|
|
* returned by \ref getAABB() and clips it to \a box.
|
|
*/
|
|
virtual AABB getClippedAABB(const AABB &box) const;
|
|
|
|
/**
|
|
* \brief Create a triangle mesh approximation of this shape
|
|
*
|
|
* This function is used by the realtime preview and
|
|
* certain integrators, which rely on hardware rasterization.
|
|
*
|
|
* The default implementation simply returns \a NULL.
|
|
*/
|
|
virtual ref<TriMesh> createTriMesh();
|
|
|
|
//! @}
|
|
// =============================================================
|
|
|
|
// =============================================================
|
|
//! @{ \name Ray tracing routines
|
|
// =============================================================
|
|
|
|
/**
|
|
* \brief Fast ray intersection test
|
|
*
|
|
* Check whether the shape is intersected by the given ray. Some
|
|
* temporary space (\ref MTS_KD_INTERSECTION_TEMP-4 bytes) is,
|
|
* supplied which can be used to cache information about the
|
|
* intersection. The function \ref fillIntersectionRecord()
|
|
* can later use this information to fill in a detailed
|
|
* intersection record.
|
|
*
|
|
* \remark In Python, this function also calls \c fillIntersectionRecord
|
|
* and has the signature
|
|
* <tt>intersection = shape.rayIntersect(ray, mint, maxt)</tt>
|
|
*/
|
|
virtual bool rayIntersect(const Ray &ray, Float mint,
|
|
Float maxt, Float &t, void *temp) const;
|
|
|
|
/**
|
|
* \brief Fast ray intersection test for visibility queries
|
|
*
|
|
* Check whether the shape is intersected by the given ray.
|
|
* No details about the intersection are returned, hence the
|
|
* function is only useful for visibility queries. For most
|
|
* shapes, this will simply call forward the call to \ref
|
|
* rayIntersect. When the shape actually contains a nested
|
|
* kd-tree, some optimizations are possible.
|
|
*
|
|
* \remark This function is not exposed in Python
|
|
*/
|
|
virtual bool rayIntersect(const Ray &ray, Float mint, Float maxt) const;
|
|
|
|
/**
|
|
* \brief Given that an intersection has been found, create a
|
|
* detailed intersection record
|
|
*
|
|
* \remark This function is not directly exposed in Python.
|
|
* It is implicitly called as part of \c rayIntersect.
|
|
*/
|
|
virtual void fillIntersectionRecord(const Ray &ray,
|
|
const void *temp, Intersection &its) const;
|
|
|
|
/**
|
|
* \brief Return the derivative of the normal vector with
|
|
* respect to the UV parameterization
|
|
*
|
|
* This can be used to compute Gaussian and principal curvatures,
|
|
* amongst other things.
|
|
*
|
|
* \param its
|
|
* Intersection record associated with the query
|
|
* \param dndu
|
|
* Parameter used to store the partial derivative of the
|
|
* normal vector with respect to \c u
|
|
* \param dndv
|
|
* Parameter used to store the partial derivative of the
|
|
* normal vector with respect to \c v
|
|
* \param shadingFrame
|
|
* Specifies whether to compute the derivative of the
|
|
* geometric normal \a or the shading normal of the surface
|
|
*
|
|
* \remark In Python, the signature of this function is
|
|
* <tt>dndu, dndv = shape.getNormalDerivative(its, shadingFrame)</tt>
|
|
*/
|
|
virtual void getNormalDerivative(const Intersection &its,
|
|
Vector &dndu, Vector &dndv, bool shadingFrame = true) const;
|
|
|
|
/**
|
|
* \brief Compute the Gaussian and mean curvature at the given
|
|
* surface intersection.
|
|
*
|
|
* \param its
|
|
* Intersection record associated with the query
|
|
* \param H
|
|
* Parameter used to store the mean curvature
|
|
* \param K
|
|
* Parameter used to store the Gaussian curvature
|
|
* \param shadingFrame
|
|
* Specifies whether to compute the curvature based on the
|
|
* geometric normal \a or the shading normal of the surface
|
|
*
|
|
* \remark In Python, the signature of this function is
|
|
* <tt>H, K = shape.getCurvature(its, shadingFrame)</tt>
|
|
*/
|
|
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)
|
|
*
|
|
* This function is used by the kd-tree visualization in
|
|
* the interactive walkthrough. The default implementation
|
|
* simply returns NULL.
|
|
*
|
|
* \remark This function is not exposed in Python
|
|
*/
|
|
virtual const KDTreeBase<AABB> *getKDTree() const;
|
|
|
|
//! @}
|
|
// =============================================================
|
|
|
|
// =============================================================
|
|
//! @{ \name Sampling routines
|
|
// =============================================================
|
|
|
|
/**
|
|
* \brief Sample a point on the surface of this shape instance
|
|
* (with respect to the area measure)
|
|
*
|
|
* The returned sample density will be uniform over the surface.
|
|
*
|
|
* \param pRec
|
|
* A position record, which will be used to return the sampled
|
|
* position, as well as auxilary information about the sample.
|
|
*
|
|
* \param sample
|
|
* A uniformly distributed 2D vector
|
|
*/
|
|
virtual void samplePosition(PositionSamplingRecord &pRec,
|
|
const Point2 &sample) const;
|
|
|
|
/**
|
|
* \brief Query the probability density of \ref samplePosition() for
|
|
* a particular point on the surface.
|
|
*
|
|
* This method will generally return the inverse of the surface area.
|
|
*
|
|
* \param pRec
|
|
* A position record, which will be used to return the sampled
|
|
* position, as well as auxilary information about the sample.
|
|
*/
|
|
|
|
virtual Float pdfPosition(const PositionSamplingRecord &pRec) const;
|
|
|
|
/**
|
|
* \brief Sample a point on the surface of this shape instance
|
|
* (with respect to the solid angle measure)
|
|
*
|
|
* The sample density should ideally be uniform in direction as seen from
|
|
* the reference point \c dRec.p.
|
|
*
|
|
* This general approach for sampling positions is named "direct" sampling
|
|
* throughout Mitsuba motivated by direct illumination rendering techniques,
|
|
* which represent the most important application.
|
|
*
|
|
* When no implementation of this function is supplied, the \ref Shape
|
|
* class will revert to the default approach, which piggybacks on
|
|
* \ref sampleArea(). This usually results in a a suboptimal sample
|
|
* placement, which can manifest itself in the form of high variance
|
|
*
|
|
* \param dRec
|
|
* A direct sampling record that specifies the reference point and a
|
|
* time value. After the function terminates, it will be populated
|
|
* with the position sample and related information
|
|
*
|
|
* \param sample
|
|
* A uniformly distributed 2D vector
|
|
*/
|
|
virtual void sampleDirect(DirectSamplingRecord &dRec,
|
|
const Point2 &sample) const;
|
|
|
|
/**
|
|
* \brief Query the probability density of \ref sampleDirect() for
|
|
* a particular point on the surface.
|
|
*
|
|
* \param dRec
|
|
* A direct sampling record, which specifies the query
|
|
* location. Note that this record need not be completely
|
|
* filled out. The important fields are \c p, \c n, \c ref,
|
|
* \c dist, \c d, \c measure, and \c uv.
|
|
*
|
|
* \param p
|
|
* An arbitrary point used to define the solid angle measure
|
|
*/
|
|
virtual Float pdfDirect(const DirectSamplingRecord &dRec) const;
|
|
|
|
//! @}
|
|
// =============================================================
|
|
|
|
// =============================================================
|
|
//! @{ \name Miscellaneous
|
|
// =============================================================
|
|
|
|
/// Does the surface of this shape mark a medium transition?
|
|
inline bool isMediumTransition() const { return m_interiorMedium.get() || m_exteriorMedium.get(); }
|
|
/// Return the medium that lies on the interior of this shape (\c NULL == vacuum)
|
|
inline Medium *getInteriorMedium() { return m_interiorMedium; }
|
|
/// Return the medium that lies on the interior of this shape (\c NULL == vacuum, const version)
|
|
inline const Medium *getInteriorMedium() const { return m_interiorMedium.get(); }
|
|
/// Return the medium that lies on the exterior of this shape (\c NULL == vacuum)
|
|
inline Medium *getExteriorMedium() { return m_exteriorMedium; }
|
|
/// Return the medium that lies on the exterior of this shape (\c NULL == vacuum, const version)
|
|
inline const Medium *getExteriorMedium() const { return m_exteriorMedium.get(); }
|
|
|
|
/// Does this shape have a sub-surface integrator?
|
|
inline bool hasSubsurface() const { return m_subsurface.get() != NULL; }
|
|
/// Return the associated sub-surface integrator
|
|
inline Subsurface *getSubsurface() { return m_subsurface; }
|
|
/// Return the associated sub-surface integrator
|
|
inline const Subsurface *getSubsurface() const { return m_subsurface.get(); }
|
|
|
|
/// Is this shape also an area emitter?
|
|
inline bool isEmitter() const { return m_emitter.get() != NULL; }
|
|
/// Return the associated emitter (if any)
|
|
inline Emitter *getEmitter() { return m_emitter; }
|
|
/// Return the associated emitter (if any)
|
|
inline const Emitter *getEmitter() const { return m_emitter.get(); }
|
|
/// Set the emitter of this shape
|
|
inline void setEmitter(Emitter *emitter) { m_emitter = emitter; }
|
|
|
|
/// Is this shape also an area sensor?
|
|
inline bool isSensor() const { return m_sensor.get() != NULL; }
|
|
/// Return the associated sensor (if any)
|
|
inline Sensor *getSensor() { return m_sensor; }
|
|
/// Return the associated sensor (if any)
|
|
inline const Sensor *getSensor() const { return m_sensor.get(); }
|
|
|
|
/// Does the shape have a BSDF?
|
|
inline bool hasBSDF() const { return m_bsdf.get() != NULL; }
|
|
/// Return the shape's BSDF
|
|
inline const BSDF *getBSDF() const { return m_bsdf.get(); }
|
|
/// Return the shape's BSDF
|
|
inline BSDF *getBSDF() { return m_bsdf.get(); }
|
|
/// Set the BSDF of this shape
|
|
inline void setBSDF(BSDF *bsdf) { m_bsdf = bsdf; }
|
|
|
|
/**
|
|
* \brief Return the number of primitives (triangles, hairs, ..)
|
|
* contributed to the scene by this shape
|
|
*
|
|
* Does not include instanced geometry
|
|
*/
|
|
virtual size_t getPrimitiveCount() const = 0;
|
|
|
|
/**
|
|
* \brief Return the number of primitives (triangles, hairs, ..)
|
|
* contributed to the scene by this shape
|
|
*
|
|
* Includes instanced geometry
|
|
*/
|
|
virtual size_t getEffectivePrimitiveCount() const = 0;
|
|
|
|
/// Copy attachments (BSDF, Emitter, ..) from another shape
|
|
void copyAttachments(Shape *shape);
|
|
|
|
//! @}
|
|
// =============================================================
|
|
|
|
// =============================================================
|
|
//! @{ \name ConfigurableObject interface
|
|
// =============================================================
|
|
|
|
/// Called once after constructing the object
|
|
virtual void configure();
|
|
|
|
/// Serialize this shape to a stream
|
|
virtual void serialize(Stream *stream, InstanceManager *manager) const;
|
|
|
|
/// Add a child (e.g. a emitter/sub surface integrator) to this shape
|
|
void addChild(const std::string &name, ConfigurableObject *child);
|
|
|
|
/// Add an unnamed child
|
|
inline void addChild(ConfigurableObject *child) { addChild("", child); }
|
|
|
|
//! @}
|
|
// =============================================================
|
|
|
|
MTS_DECLARE_CLASS()
|
|
protected:
|
|
/// Create a new shape
|
|
Shape(const Properties &props);
|
|
|
|
/// Unserialize a shape
|
|
Shape(Stream *stream, InstanceManager *manager);
|
|
|
|
/// Virtual destructor
|
|
virtual ~Shape();
|
|
protected:
|
|
std::string m_name;
|
|
ref<BSDF> m_bsdf;
|
|
ref<Subsurface> m_subsurface;
|
|
ref<Emitter> m_emitter;
|
|
ref<Sensor> m_sensor;
|
|
ref<Medium> m_interiorMedium;
|
|
ref<Medium> m_exteriorMedium;
|
|
};
|
|
|
|
MTS_NAMESPACE_END
|
|
|
|
#endif /* __MITSUBA_RENDER_SHAPE_H_ */
|
|
|
|
|