Support Forum G3D Web Page |
Local surface geometry + BSDF + emission function.
More...
Inherits G3D::ReferenceCountedObject.
Inherited by G3D::UniversalSurfel.
Classes | |
class | ExpressiveParameters |
Non-physical manipulations of the BSDF commonly employed for expressive rendering effects. More... | |
class | Impulse |
A BSDF impulse ("delta function"). More... | |
struct | Source |
Mostly for debugging. More... | |
Public Types | |
typedef SmallArray< Impulse, 2 > | ImpulseArray |
Impulses in the BSDF. More... | |
Public Member Functions | |
Surfel () | |
virtual | ~Surfel () |
virtual Radiance3 | emittedRadiance (const Vector3 &wo) const |
Returns the radiance emitted by this surface in direction wo. More... | |
virtual Color3 | finiteScatteringDensity (const Vector3 &wi, const Vector3 &wo, const ExpressiveParameters &expressiveParameters=ExpressiveParameters()) const =0 |
Evaluates the finite portion of . More... | |
virtual Color3 | finiteScatteringDensity (PathDirection pathDirection, const Vector3 &wFrom, const Vector3 &wTo, const ExpressiveParameters &expressiveParameters=ExpressiveParameters()) const |
Provided as a convenience helper method for implementers of scatter(). More... | |
virtual void | getImpulses (PathDirection direction, const Vector3 &w, ImpulseArray &impulseArray, const ExpressiveParameters &expressiveParameters=ExpressiveParameters()) const =0 |
Given w, returns all wo directions that yield impulses in for PathDirection::SOURCE_TO_EYE paths, and vice versa for PathDirection::EYE_TO_SOURCE paths. More... | |
bool | isLight () const |
True if this surfel was produced by a surface that came from a Light, and thus may have emissive terms that are already accounted for by direct illumination. More... | |
virtual bool | nonZeroFiniteScattering () const |
True if this surfel's finiteScatteringDensity function ever returns a non-zero value. More... | |
virtual Color3 | probabilityOfScattering (PathDirection pathDirection, const Vector3 &w, Random &rng, const ExpressiveParameters &expressiveParameters=ExpressiveParameters()) const |
Given direction w, returns the a priori probability of scattering in any direction (vs. More... | |
virtual Color3 | reflectivity (Random &rng, const ExpressiveParameters &expressiveParameters=ExpressiveParameters()) const |
Approximate reflectivity of this surface, primarily used for ambient terms. More... | |
virtual bool | scatter (PathDirection pathDirection, const Vector3 &w_before, bool russianRoulette, Random &rng, Color3 &weight, Vector3 &w_after, bool &impulseScattered=ignoreBool, float &probabilityHint=ignore, const ExpressiveParameters &expressiveParameters=ExpressiveParameters()) const |
Computes the direction of a scattered photon and a weight that compensates for the way that the the sampling process is performed. More... | |
virtual void | transformToWorldSpace (const CoordinateFrame &xform) |
Transform this to world space using the provided xform. More... | |
virtual bool | transmissive () const |
Must return true if a ray is ever scattered to the opposite side of the surface with respect to the Surfel::shadingNormal. More... | |
Public Attributes | |
float | etaRatio = 1.0f |
Ratio of complex refractive indices for each side of the interface. More... | |
uint8 | flags = 0 |
0x1 = light flag More... | |
Vector3 | geometricNormal |
The normal to the true underlying geometry of the patch that was sampled (e.g., the face normal). More... | |
Color3 | kappaNeg |
Ratio of complex refractive indices for each side of the interface. More... | |
Color3 | kappaPos |
Ratio of complex refractive indices for each side of the interface. More... | |
const Material * | material |
The material that generated this Surfel. More... | |
Point3 | position |
Point in world space at the geometric center of this surfel. More... | |
Point3 | prevPosition |
Point in world space at the geometric center of this surfel in the previously rendered frame of animation. More... | |
Vector3 | shadingNormal |
The normal to the patch for shading purposes, i.e., after normal mapping. More... | |
Vector3 | shadingTangent1 |
Primary tangent vector for use in shading anisotropic surfaces. More... | |
Vector3 | shadingTangent2 |
Secondary shading tangent. More... | |
struct G3D::Surfel::Source | source |
const Surface * | surface |
The surface that generated this Surfel. More... | |
Static Public Attributes | |
static float | ignore |
static bool | ignoreBool |
Protected Member Functions | |
Surfel (const Point3 &position, const Point3 &prevPosition, const Vector3 &geometricNormal, const Vector3 &shadingNormal, const Vector3 &shadingTangent1, const Vector3 &shadingTangent2, const float etaPos, const Color3 &kappaPos, const float etaNeg, const Color3 &kappaNeg, const uint8 flags, const Source &source, const Material *material, const Surface *surface) | |
virtual void | sampleFiniteDirectionPDF (PathDirection pathDirection, const Vector3 &w_o, Random &rng, const ExpressiveParameters &expressiveParameters, Vector3 &w_i, float &pdfValue) const |
Called by the default implementation of scatter. More... | |
Static Protected Member Functions | |
template<class T , class ... ArgTypes> | |
static shared_ptr< T > | createShared (ArgTypes &&... args) |
Like std::make_shared, but works for protected constructors. More... | |
Local surface geometry + BSDF + emission function.
The Surfel models the interface between two homogeneous media at a small patch on a surface. It is oriented, and the normal is used to give orientation to distinguish the two sides. This combines the mathematical models of a BSDF, and emission function, and a surface patch.
Scene geometric sampling functions (e.g., ray intersection) return Surfel subclasses that have been initialized with the appropriate coefficients for that location in the scene (i.e., they sample the texture map).
All vectors and positions are in world space. In this documentation,
The BSDF ( ) must obey the following constraints:
Most methods require a PathDirection because transmissive BSDFs are different depending on whether the path denotes a photon moving along its physical direction of propagation or a virtual path backwards from an eye. For non-transmissive BSDFs the result is the same either way.
scatter() returns a weight that compensates for distortion of the sampling distribution within the functions. When the scattering is non refractive, the caller must adjust the power or radiance scattered by this weight:
The refractive case requires more care. If you're are tracing paths that will be connected as rays as in ray tracing or path tracing, then at a refractive interface you must adjust the radiance by:
after invoking scatterIn or scatterOut when the path refracts. You can detect the refractive case by:
However, if you're tracing paths that represent photons that will be gathered to estimate radiance by:
then adjust the power after scatter() by:
In this case, the divergence (or convergence) of the photons at a refractive interface will naturally be captured by the number of photons within gatherArea and no explicit correction is required.
For subclass implementers:
If it is computationally harder to importance sample than to trace rays, make the scatter functions use weights and select directions naively (e.g., uniformly). In this case, more rays will be needed for convergence because the amount of energy they contribute to the final signal will have high variance.
If it is computationally harder to trace rays than to importance sample, then it is worth spending a longer time on importance sampling to drive the weights close to 1.0, meaning that each ray contributes approximately the same energy towards convergence of the image.
Of course, the Surfel implementor cannot make these decisions in the context of a single class–they are end-to-end decisions for an entire system.
typedef SmallArray<Impulse, 2> G3D::Surfel::ImpulseArray |
Impulses in the BSDF.
This contains three inline-allocated elements to support reflection and refraction without heap allocation.
|
protected |
|
inline |
|
inlinevirtual |
|
inlinestaticprotectedinherited |
Like std::make_shared, but works for protected constructors.
Call as createShared<myclass>.
Returns the radiance emitted by this surface in direction wo.
This models an emission function.
Defaults to zero. N.B. A "Lambertian emitter", which is often considered the ideal area light source, would return a constant value on the side
Note that this interface is intentionally insufficient for representing a point light, which requires a biradiance function.
If this function returns a non-zero value, then emissive() must return true.
Reimplemented in G3D::UniversalSurfel.
|
pure virtual |
Evaluates the finite portion of .
This is the straightforward abstraction of the BSDF, i.e., "forward BSDF evaluation". It is useful for direct illumination and in the gather kernel of a ray tracer. Note that this does not scale the result by .
It omits the impulses because they would force the return value to infinity.
wi | Unit vector pointing backwards along the direction from which light came ("to the light source") |
wi | Unit vector pointing out in the direction that light will go ("to the eye") |
Implemented in G3D::UniversalSurfel.
|
virtual |
Provided as a convenience helper method for implementers of scatter().
Allows programmatically swapping the directions (which only matters for refraction if the BSDF is reciprocal).
finiteScatteringDensity(PathDirection::SOURCE_TO_EYE, wi, wo)
= finiteScatteringDensity(PathDirection::EYE_TO_SOURCE, wo, wi)
=
|
pure virtual |
Given w, returns all wo directions that yield impulses in for PathDirection::SOURCE_TO_EYE paths, and vice versa for PathDirection::EYE_TO_SOURCE paths.
Overwrites the impulseArray.
For example, getImpulses(PathDirection::SOURCE_TO_EYE, wi, impulseArray)
returns the impulses for scattering a photon emitted from a light.
getImpulses(PathDirection::EYE_TO_SOURCE, wo, impulseArray)
returns the impulses for scattering a backwards-traced ray from the ey.
Implemented in G3D::UniversalSurfel.
|
inline |
True if this surfel was produced by a surface that came from a Light, and thus may have emissive terms that are already accounted for by direct illumination.
|
inlinevirtual |
True if this surfel's finiteScatteringDensity function ever returns a non-zero value.
(May also be true even if it does only ever return zero, however).
Reimplemented in G3D::UniversalSurfel.
|
virtual |
Given direction w, returns the a priori probability of scattering in any direction (vs.
absorption), which is the directional-hemispherical reflectance and transmittance when tracing PathDirection::EYE_TO_SOURCE and hemispherical-directional reflectance and transmittance when tracing PathDirection::SOURCE_TO_EYE:
This method is invoked by scatter().
By default, the probability computed by sampling evaluateFiniteScatteringDensity() and getImpulses(). BSDFs that have analytic integrals can override these methods to execute more efficiently.
The return value is necessarily on [0, 1] for each frequency unless non-default expressive parameters are used.
Reimplemented in G3D::UniversalSurfel.
|
virtual |
Approximate reflectivity of this surface, primarily used for ambient terms.
The default implementation invokes probabilityOfScattering many times and is not very efficient.
Reimplemented in G3D::UniversalSurfel.
|
protectedvirtual |
Called by the default implementation of scatter.
Samples a directional PDF
Samples from some distribution on the sphere. This is optimal if proportional to , where is the finite portion of the BSDF (no impulses) but can be anything that is nonzero where $f$ is nonzero.
Returns w_i = and pdfValue =
Reimplemented in G3D::UniversalSurfel.
|
virtual |
Computes the direction of a scattered photon
and a weight that compensates for the way that the the sampling process is performed.
For use in Monte Carlo integration of the rendering equation, this computes the cosine-weighted BSDF term.
The weight is needed to allow efficient computation of scattering from BSDFs that have no computationally efficient method for exact analytic sampling. The caller should scale the radiance or power transported by the weight.
scatter(PathDirection::SOURCE_TO_EYE, wi, ..., wo)
scatter(PathDirection::EYE_TO_SOURCE, wo, ..., wi)
Let h(w)
be the PDF that the implementation actually samples with respect to. Let g(w) = f(w_before, w_after) |w_after.dot(n)|
, the function that scatter samples. [Note: g(w)
is not a PDF; just the terms from the integrand of the rendering equation]
The function produces two outputs:
Note that the weight might be zero even if the photon scatters, for example, a perfectly "red" photon striking a perfectly "green" surface would have a weight of zero.
The probabilityHint is for use by photon mappers to decrease convergence time. If the a priori probability density of scattering in this direction was infinity, it returns 1.0. If the density was 0.0, it returns 0. For finite densities it scales between them.
If russianRoulette is true, then with probability proportional to the initial weight paths will be terminated. Nonterminated paths have weights increased proportionally to maintain the mean. (This is useful for photon mapping and pure path tracing.) The weight will be zero if the path terminates.
Note that because they are driven by the finite portion of the BSDF, weights returned must be non-negative and finite, but are not bounded. However, an efficient importance-sampling implementation will return weights close to 1.0.
The default implementation relies on getIncoming() and inefficient cosine (vs. importance) sampling against evaluateFiniteScatteringDensity(). Thus although it will work for any evaluateFiniteScatteringDensity() implementation, it is desirable to optimize the implementation of scatter() in subclasses where possible.
Consider this in the context of Monte Carlo integration of . For that integral, choose samples and weight as described below, and then multiply each by the corresponding and sum.
This is single-importance sampling based on scattering. it gives good convergence when is uniform, and is often the best we can do and is at least correct otherwise.
Here are several different ways of implementing this method for a common example of a perfectly lambertian (f() = 1 / pif()
) BRDF.
A noise-minimizing implementation:
Uniformly random hemisphere implementation:
Uniformly random sphere functions:
There are of course a limitless number of ways of implementing the scattering.
Returns true if the weight is nonzero.
|
virtual |
Transform this to world space using the provided xform.
|
inlinevirtual |
Must return true if a ray is ever scattered to the opposite side of the surface with respect to the Surfel::shadingNormal.
This may conservatively always return true (which is the default implementation). Setting this correctly doubles the efficiency of the default implementation of other methods.
There is no equivalent reflective() method because all physical transmissive surfaces are also reflective, so it would rarely be false in practice.
Reimplemented in G3D::UniversalSurfel.
float G3D::Surfel::etaRatio = 1.0f |
Ratio of complex refractive indices for each side of the interface.
eta ( ) is the real part, which determines the angle of refraction. kappa ( ) is the imaginary part, which determines absorption within the medium.
For a non-transmissive medium, eta should be NaN() and kappa should be Color3::inf().
The "Pos" versions are for the material on the side of the surface that the geometricNormal faces towards. The "Neg" versions are for the material on the side opposite the geometricNormal.
We ignore the frequency-variation in eta, since three color samples isn't enough to produce meaningful chromatic dispersion anyway.
uint8 G3D::Surfel::flags = 0 |
Vector3 G3D::Surfel::geometricNormal |
The normal to the true underlying geometry of the patch that was sampled (e.g., the face normal).
This is often useful for ray bumping.
Always a unit vector.
|
static |
|
static |
Color3 G3D::Surfel::kappaNeg |
Ratio of complex refractive indices for each side of the interface.
eta ( ) is the real part, which determines the angle of refraction. kappa ( ) is the imaginary part, which determines absorption within the medium.
For a non-transmissive medium, eta should be NaN() and kappa should be Color3::inf().
The "Pos" versions are for the material on the side of the surface that the geometricNormal faces towards. The "Neg" versions are for the material on the side opposite the geometricNormal.
We ignore the frequency-variation in eta, since three color samples isn't enough to produce meaningful chromatic dispersion anyway.
Color3 G3D::Surfel::kappaPos |
Ratio of complex refractive indices for each side of the interface.
eta ( ) is the real part, which determines the angle of refraction. kappa ( ) is the imaginary part, which determines absorption within the medium.
For a non-transmissive medium, eta should be NaN() and kappa should be Color3::inf().
The "Pos" versions are for the material on the side of the surface that the geometricNormal faces towards. The "Neg" versions are for the material on the side opposite the geometricNormal.
We ignore the frequency-variation in eta, since three color samples isn't enough to produce meaningful chromatic dispersion anyway.
const Material* G3D::Surfel::material |
The material that generated this Surfel.
May be nullptr. This is a raw pointer because incrementing a shared_ptr is expensive during material sampling.
Point3 G3D::Surfel::position |
Point in world space at the geometric center of this surfel.
Point3 G3D::Surfel::prevPosition |
Point in world space at the geometric center of this surfel in the previously rendered frame of animation.
Useful for computing velocity.
Vector3 G3D::Surfel::shadingNormal |
The normal to the patch for shading purposes, i.e., after normal mapping.
e.g., the interpolated vertex normal or normal-mapped normal.
Always a unit vector.
Vector3 G3D::Surfel::shadingTangent1 |
Primary tangent vector for use in shading anisotropic surfaces.
This is the tangent space after normal mapping has been applied.
Vector3 G3D::Surfel::shadingTangent2 |
Secondary shading tangent.
struct G3D::Surfel::Source G3D::Surfel::source |