Overview
Writing a PBR surface shader involves designing a bidirectional scattering distribution function (BSDF) for the surface. This function describes how light scatters when it hits the surface. BSDFs are an opaque data type in VEX that you can store and operate on much like other primitive types.
You output the final BSDF for the the shader through a new global variable F. In VOPs, you connect a BSDF to the F connection of the output node (see VOPs below).
The BSDF is a self-contained description of how a surface reflects light. With PBR, you don’t need to compute illumination (for example, using
illuminanceloops or trace() calls). You only need to provide a bsdf.
You don’t write the scattering function yourself. You create BSDFs by combining primitive BSDFs using addition, multiplication, and scalar multiplication. See “primitive BSDFs” and “combining BSDFs” below.
Depending on the settings selected for the render, mantra can use the BSDFs calculated by your shader in many different ways. For example, it may perform direct lighting, indirect lighting, or evaluate lighting in reverse for algorithms like photon mapping.
You can design shaders that support both traditional and physically based rendering. You just need to assign values to both types of output variables (Cf, Of, and Af for traditional rendering, F for PBR rendering) in your shader.
Primitive BSDFs
phong
bsdf phong(float exponent)bsdf phong(vector nml, float exponent)
A phong reflection.
exponent- phong exponent.
phonglobe
bsdf phonglobe(vector dir, float exponent)bsdf phonglobe(vector dir, vector nml, float exponent)bsdf phonglobe(vector dir, float exponentx, float exponenty, vector framex, vector framey)bsdf phonglobe(vector dir, vector nml, float exponentx, float exponenty, vector framex, vector framey)
A phong (blurred) reflection along a given direction vector. This will produce the same result as phong() when the direction vector is the reflection vector, but with this function you can also gather illumination from other directions (such as transmission).
It is possible to create anisotropic phong lobes by providing x and y exponents and tangent vectors.
dir– the direction of specularity.nml– optional normal to specify the hemisphere for reflection directions.exponent– phong exponent.exponentx– phong exponent along theframexvector.exponenty– phong exponent along theframeyvector.framex– highlight X directionframey– highlight Y direction
ashikhmin
bsdf ashikhmin(float exponentx, float exponenty, vector framex, vector framey)bsdf ashikhmin(vector nml, float exponentx, float exponenty, vector framex, vector framey)
An anisotropic bsdf similar to phong() but with independent controls for the highlight size along 2 tangent vectors.
exponentx– phong exponent along theframexvector.exponenty– phong exponent along theframeyvector.framex– highlight X direction.framey– highlight Y direction.
blinn
bsdf blinn(float exponent)bsdf blinn(vector nml, float exponent)
A blinn highlight.
exponent– blinn exponent.
matchvex_blinn
bsdf matchvex_blinn(float exponent)bsdf matchvex_blinn(vector nml, float exponent)
The BSDF produced by blinn is not the same as the traditional VEX blinn() output. Use this function to produce a closer approximate match to the traditional VEX blinn().
specular
bsdf specular(vector dir)
A mirror specular reflection along a given direction vector.
dir– the direction of specularity.
matchvex_specular
bsdf matchvex_specular(float exponent)bsdf matchvex_specular(vector nml, float exponent)
The BSDF produced by specular is not the same as the traditional VEX specular() output. Use this function to produce a closer approximate match to the traditional VEX specular().
cone
A cone reflection along a given direction vector. This BSDF is constant within the given angle, producing a similar result to the gather or irradiance loops.
dir– the direction of specularity.angle– cone angle in radians.
diffuse
bsdf diffuse()bsdf diffuse(vector nml)
Diffuse reflections. This BSDF has an albedo of 0.5.
wireblinn
bsdf wireblinn(vector tangent, float exponent)
Blinn function defined around a tangent vector. You can use this to produce the average specular illumination for thin wire-like primitives such as hair.
tangent– tangent vector along the hair.exponent– blinn exponent.
wirediffuse
bsdf wirediffuse(vector tangent)
Diffuse function defined around a tangent vector. This can be used to produce the average diffuse illumination for thin wire-like primitives such as hair.
tangent- tangent vector along the hair.
Combining BSDFs
bsdf +(bsdf, bsdf)Sum together two bsdfs. Summing bsdfs allows you to include more than one type of component, such as summing together a diffuse() and a phong().
bsdf *(float scale, bsdf)bsdf *(vector scale, bsdf)Scale a bsdf by a color or a scale factor. Scaling a bsdf can allow you to incorporate surface colors (such as texturing) into the bsdf.
bsdf *(bsdf, bsdf)Create the produce of two bsdfs. This function is most useful for scaling a specular bsdf by a diffuse().
vector albedo(bsdf)Return the portion of reflected light for a
bsdf. The return value should be between 0 and 1 for bsdfs that conserve energy. The albedo for a default diffusebsdfis 0.5, but will change based on vector scale factors and otherbsdfcomponents.
VOPs
You can build a PBR shader using VOPs, by generating a BSDF (yellow) output and piping it to the F connection of the output node. Most traditional lighting VOPs now generate a bsdf output in addition to the traditional outputs.
This is an example of a VOP network that creates a specular bsdf and diffuse bsdf, adds them together (in add1), and sends the resulting bsdf to the output.