Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added initial draft for OSL closures #614

Merged
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
220 changes: 220 additions & 0 deletions libraries/stdlib/osl/stdosl.h
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,226 @@ closure color volume_matte() BUILTIN;
closure color subsurface(float eta, float g, color mfp, color albedo) BUILTIN;
#endif

// ******************* MATERIALX PBS LIBRARY CLOSURES - DRAFT BEGIN ******************* //

// -------------------------------------------------------------//
// BSDF closures //
// -------------------------------------------------------------//
// Constructs a diffuse reflection BSDF based on the Oren-Nayar reflectance model.
//
// \param N Normal vector of the surface point beeing shaded.
// \param albedo Surface albedo.
// \param roughness Surface roughness [0,1]. A value of 0.0 gives Lambertian reflectance.
//
closure color oren_nayar_diffuse_bsdf(normal N, color albedo, float roughness) BUILTIN;
// Constructs a diffuse reflection BSDF based on the corresponding component of
// the Disney Principled shading model.
//
// \param N Normal vector of the surface point beeing shaded.
// \param albedo Surface albedo.
// \param roughness Surface roughness [0,1].
//
closure color burley_diffuse_bsdf(normal N, color albedo, float roughness) BUILTIN;
// Constructs a reflection and/or transmission BSDF based on a microfacet reflectance
// model and a Fresnel curve for dielectrics. The two tint parameters control the
// contribution of each reflection/transmission lobe. The tints should remain 100% white
// for a physically correct dielectric, but can be tweaked for artistic control or set
// to 0.0 for disabling a lobe.
// The closure may be vertically layered over a base BSDF for the surface beneath the
// dielectric layer. This is done using the layer() closure. By chaining multiple
// dielectric_bsdf closures you can describe a surface with multiple specular lobes.
// If transmission is enabled (transmission_tint > 0.0) the closure may be layered over
// a VDF closure describing the surface interior to handle absorption and scattering
// inside the medium.
//
// \param N Normal vector of the surface point beeing shaded.
// \param U Tangent vector of the surface point beeing shaded.
// \param reflection_tint Weight per color channel for the reflection lobe. Should be (1,1,1) for a physically-correct dielectric surface,
// but can be tweaked for artistic control. Set to (0,0,0) to disable reflection.
// \param transmission_tint Weight per color channel for the transmission lobe. Should be (1,1,1) for a physically-correct dielectric surface,
// but can be tweaked for artistic control. Set to (0,0,0) to disable transmission.
// \param roughness_x Surface roughness in the U direction. Valid range [0,1] with a perceptually linear response over the range.
// \param roughness_y Surface roughness in the V direction. Valid range [0,1] with a perceptually linear response over the range.
// \param ior Refraction index.
// \param distribution Microfacet distribution. An implementation is expected to support the following distributions: { "ggx" }
//
closure color dielectric_bsdf(normal N, vector U, color reflection_tint, color transmission_tint, float roughness_x, float roughness_y, float ior, string distribution) BUILTIN;
// Constructs a reflection BSDF based on a microfacet reflectance model.
// Uses a Fresnel curve with complex refraction index for conductors/metals.
// If an artistic parametrization is preferred the artistic_ior() utility function
// can be used to convert from artistic to physical parameters.
//
// \param N Normal vector of the surface point beeing shaded.
// \param U Tangent vector of the surface point beeing shaded.
// \param roughness_x Surface roughness in the U direction. Valid range [0,1] with a perceptually linear response over the range.
niklasharrysson marked this conversation as resolved.
Show resolved Hide resolved
// \param roughness_y Surface roughness in the V direction. Valid range [0,1] with a perceptually linear response over the range.
// \param ior Refraction index.
// \param extinction Extinction coefficient.
// \param distribution Microfacet distribution. An implementation is expected to support the following distributions: { "ggx" }
//
closure color conductor_bsdf(normal N, vector U, float roughness_x, float roughness_y, color ior, color extinction, string distribution) BUILTIN;
niklasharrysson marked this conversation as resolved.
Show resolved Hide resolved
// Constructs a reflection and/or transmission BSDF based on a microfacet reflectance model
// and a generalized Schlick Fresnel curve. The two tint parameters control the contribution
// of each reflection/transmission lobe.
// The closure may be vertically layered over a base BSDF for the surface beneath the
// dielectric layer. This is done using the layer() closure. By chaining multiple
// dielectric_bsdf closures you can describe a surface with multiple specular lobes.
// If transmission is enabled (transmission_tint > 0.0) the closure may be layered over
// a VDF closure describing the surface interior to handle absorption and scattering
// inside the medium.
//
// \param N Normal vector of the surface point beeing shaded.
// \param U Tangent vector of the surface point beeing shaded.
// \param reflection_tint Weight per color channel for the reflection lobe. Set to (0,0,0) to disable reflection.
// \param transmission_tint Weight per color channel for the transmission lobe. Set to (0,0,0) to disable transmission.
// \param roughness_x Surface roughness in the U direction. Valid range [0,1] with a perceptually linear response over the range.
// \param roughness_y Surface roughness in the V direction. Valid range [0,1] with a perceptually linear response over the range.
// \param f0 Reflectivity per color channel at facing angles.
// \param f90 Reflectivity per color channel at grazing angles.
// \param distribution Microfacet distribution. An implementation is expected to support the following distributions: { "ggx" }
//
closure color generalized_schlick_bsdf(normal N, vector U, color reflection_tint, color transmission_tint, float roughness_x, float roughness_y, color f0, color f90, float exponent, string distribution) BUILTIN;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How is external IOR / IOR layering tracked? If it's done behind the scenes by passing the IOR ratio to the closure, that may not be enough information for the generalized Schlick BSDF closure.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nhoffman-lucasfilm That's a great question. I believe this will be tracked through the use of the medium_vdf closure that describes the medium which the light travels through before hitting a new interface. The medium_vdf has an ior parameter that is an absolute IOR value for the medium.

For the primary intersection I guess air/vacuum is assumed outside. I'm not sure how it's handled for situations where the camera starts inside, like a camera under water, but I suppose a media closure could be attached to the camera.

For cases where BSDFs are layered without the use of media in-between I think all the needed information should be available still, since IOR could be derived from the parameters on each BSDF.

But maybe people from Imageworks, Adsk/Arnold or other teams that have implemented OSL closures in practice can fill in more details here?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We attach medium data to every ray (if present). If a camera is inside some medium we find the object and evaluate the shader to grab what you're calling medium_vdf here. We also compute relative IOR outside the shader. Basically we intercept the BSDF creation from closure data and override the IOR parameters.

May be worth mentioning that we have an optional parameter to all bsdfs called "force_eta" (float from 0 to 1). This allows the shader, and the artist, to override the dynamic IOR. For instance, if the look changes too much for them when underwater, they can tone down the change.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We track the IOR of the bulk medium as the ray transmits through dielectric boundaries, via the usual priority system approach. The interior bulk medium IOR is taken from the specular lobe in the standard surface model (i.e. this lobe effectively defines the IOR of the bulk). We don't take into account IOR jumps between the various layers in the model though (e.g the coat BSDF "above" the specular layer, is not aware of the specular IOR), which is probably a reasonable approach considering the closure mixture model is a somewhat ad-hoc representation of the layered structure anyway.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't currently handle the "camera under water" situation, unfortunately. Though it seems that determining this is a matter for the renderer to handle, e.g. by casting a ray to infinity and tracking the media.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"We also compute relative IOR outside the shader. Basically we intercept the BSDF creation from closure data and override the IOR parameters" - in other words the ratio (external_ior / bulk_ior) is passed into the closure's "ior" parameter? In that case, for the generalized_schlick_bsdf closure a different parameter adjustment would be needed, adjusting f0 using something like the equations from slides 107-108 or slide 111 in https://blog.selfshadow.com/publications/s2020-shading-course/hoffman/s2020_pbs_hoffman_slides.pdf (a similar adjustment might need to be made for the f90 parameter - I've spent a little bit of time on that but don't have a formula for that one ready yet). Would this kind of closure-specific parameter adjustment be feasible, or is does that logic need to be agnostic to which closure is used?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Related question - is there a way to determine the reflection's "sidedness" inside the closure? When using IOR as a parameter, internal vs. external reflection can be easily determined from the relative IOR - if it is greater or small than 1. But 1/eta and eta produce the same value for f0, so an extra bit (literally) of information is needed to disambiguate those two cases for the generalized_schlick_bsdf closure.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not overriding the closure parameter itself, but the BSDF internal object that gets created on the renderer side. We do some translation for non-ior parametrizations, but we haven't polished that a lot, it just works. Also, this doesn't affect internal BSDF layering, we don't track stuff there.

About sidedness, our convention: The shader always puts the IOR of the front surface regardless of what side is being rendered. The implementation is responsible for doing 1/eta if on the backside. We did this to remove the burden from the shaders, but other people might have other opinions.

// Constructs a translucent (diffuse transmission) BSDF based on the Lambert reflectance model.
//
// \param N Normal vector of the surface point beeing shaded.
// \param albedo Surface albedo.
//
closure color translucent_bsdf(normal N, color albedo) BUILTIN;

// Constructs a closure that represents straight transmission through a surface.
//
// NOTE:
// - This is not a node in the MaterialX library, but the surface shader constructor
// node has an 'opacity' parameter to control textured cutout opacity.
//
closure color transparent_bsdf() BUILTIN;
// Constructs a BSSRDF for subsurface scattering within a homogeneous medium.
//
// \param N Normal vector of the surface point beeing shaded.
// \param albedo Surface albedo.
// \param sss_depth Mean-free path in units of scene length.
// \param sss_color Scattering color / transmittance. The desired color resulting from white light transmitted a distance of 'sss_depth'
// through the surface.
// \param anisotropy Scattering anisotropy [-1,1]. Negative values give backwards scattering, positive values give forward scattering,
// and 0.0 gives uniform scattering.
//
closure color subsurface_bssrdf(normal N, color albedo, float sss_depth, color sss_color, float anisotropy) BUILTIN;
niklasharrysson marked this conversation as resolved.
Show resolved Hide resolved
// Constructs a microfacet BSDF for the back-scattering properties of cloth-like materials.
// This closure may be vertically layered over a base BSDF, where energy that is not reflected
// will be transmitted to the base closure.
//
// \param N Normal vector of the surface point beeing shaded.
// \param albedo Surface albedo.
// \param roughness Surface roughness [0,1].
//
closure color sheen_bsdf(normal N, color albedo, float roughness) BUILTIN;
// Adds an iridescent thin film layer over a microfacet base BSDF. This must be layered over
niklasharrysson marked this conversation as resolved.
Show resolved Hide resolved
// another base BSDF using the layer() closure, as this is a modifier and cannot be used as a
// standalone closure.
//
// TODO:
// - This might be better to represent as optional extra arguments on the closures that do support
// thin-film iridescence (dielectric_bsdf, conductor_bsdf and generalized_schlick_bsdf)?
//
// \param thickness Thickness of the thin film.
// \param ior Refraction index of the thin film.
//
closure color thin_film_bsdf(float thickness, float ior) BUILTIN;
// -------------------------------------------------------------//
// EDF closures //
// -------------------------------------------------------------//
// Constructs an EDF emitting light uniformly in all directions.
//
// \param emittance Radiant emittance of light leaving the surface.
//
closure color uniform_edf(color emittance) BUILTIN;

// Constructs an EDF emitting light inside a cone around the normal direction.
//
// \param emittance Radiant emittance of light leaving the surface.
// \param N Cone direction vector.
niklasharrysson marked this conversation as resolved.
Show resolved Hide resolved
// \param inner_angle Angle of inner cone where emission falloff starts.
// \param outer_angle Angle of outer cone where emission goes to zero. If set to a smaller value
// than inner_angle no falloff will occur within the cone.
//
closure color conical_edf(color emittance, normal N, float inner_angle, float outer_angle) BUILTIN;
// -------------------------------------------------------------//
// VDF closures //
// -------------------------------------------------------------//
// Constructs a VDF scattering light for a participating medium, based on the Henyey-Greenstein
// phase function. Forward, backward and uniform scattering is supported and controlled by the
// anisotropy input.
//
niklasharrysson marked this conversation as resolved.
Show resolved Hide resolved
// \param albedo Volume single scattering albedo.
// \param extinction Volume extinction coefficient.
// \param anisotropy Scattering anisotropy [-1,1]. Negative values give backwards scattering, positive values give forward scattering,
// and 0.0 gives uniform scattering.
// \param ior Optional float parameter for refraction index of a homogeneous medium.
// \param priority Optional int parameter for priority of a homogeneous medium (for nested dielectrics).
niklasharrysson marked this conversation as resolved.
Show resolved Hide resolved
//
closure color anisotropic_vdf(color albedo, color extinction, float anisotropy) BUILTIN;
// -------------------------------------------------------------//
// Layering closures //
// -------------------------------------------------------------//
// Vertically layer a layerable BSDF such as dielectric_bsdf, generalized_schlick_bsdf or
// sheen_bsdf over a BSDF or VDF. The implementation is target specific, but a standard way
// of handling this is by albedo scaling, using "base*(1-reflectance(top)) + top", where
// reflectance() calculates the directional albedo of a given top BSDF.
//
// \param top Closure defining the top layer.
// \param base Closure defining the base layer.
//
// TODO:
// - This could also be achived by closure nesting where each layerable closure takes
// a closure color "base" input instead.
// - One advantage having a dedicated layer() closure is that in the future we may want to
// introduce parameters to describe the sandwitched medium between the layer interfaces.
// Such parameterization could then be added on this layer() closure as extra arguments.
// - Do we want/need parameters for the medium here now, or do we look at that later?
//
closure color layer(closure color top, closure color base) BUILTIN;

// NOTE: For "horisontal layering" closure mix() already exists in OSL.
// -------------------------------------------------------------//
// Utility functions //
// -------------------------------------------------------------//
// Converts the artistic parameterization reflectivity and edge_color to complex IOR values.
// To be used with the conductor_bsdf() closure.
// [OG14] "Artist Friendly Metallic Fresnel", http://jcgt.org/published/0003/04/03/paper.pdf
//
// \param reflectivity Reflectivity per color channel at facing angles ('r' parameter in [OG14]).
// \param edge_tint Color bias for grazing angles ('g' parameter in [OG14]).
// NOTE: This is not equal to 'f90' in a Schlick Fresnel parameterization.
// \param ior Output refraction index.
// \param extinction Output extinction coefficient.
//
void artistic_ior(color reflectivity, color edge_tint, output color ior, output color extinction);

// ******************* MATERIALX PBS LIBRARY CLOSURES - DRAFT END ******************* //


// Renderer state
int backfacing () BUILTIN;
int raytype (string typename) BUILTIN;
Expand Down