Shader: Add Metallic BSDF Node #114958
No reviewers
Labels
No Label
Interest
Alembic
Interest
Animation & Rigging
Interest
Asset System
Interest
Audio
Interest
Automated Testing
Interest
Blender Asset Bundle
Interest
BlendFile
Interest
Code Documentation
Interest
Collada
Interest
Compatibility
Interest
Compositing
Interest
Core
Interest
Cycles
Interest
Dependency Graph
Interest
Development Management
Interest
EEVEE
Interest
Freestyle
Interest
Geometry Nodes
Interest
Grease Pencil
Interest
ID Management
Interest
Images & Movies
Interest
Import Export
Interest
Line Art
Interest
Masking
Interest
Metal
Interest
Modeling
Interest
Modifiers
Interest
Motion Tracking
Interest
Nodes & Physics
Interest
OpenGL
Interest
Overlay
Interest
Overrides
Interest
Performance
Interest
Physics
Interest
Pipeline, Assets & IO
Interest
Platforms, Builds & Tests
Interest
Python API
Interest
Render & Cycles
Interest
Render Pipeline
Interest
Sculpt, Paint & Texture
Interest
Text Editor
Interest
Translations
Interest
Triaging
Interest
Undo
Interest
USD
Interest
User Interface
Interest
UV Editing
Interest
VFX & Video
Interest
Video Sequencer
Interest
Viewport & EEVEE
Interest
Virtual Reality
Interest
Vulkan
Interest
Wayland
Interest
Workbench
Interest: X11
Legacy
Asset Browser Project
Legacy
Blender 2.8 Project
Legacy
Milestone 1: Basic, Local Asset Browser
Legacy
OpenGL Error
Meta
Good First Issue
Meta
Papercut
Meta
Retrospective
Meta
Security
Module
Animation & Rigging
Module
Core
Module
Development Management
Module
Grease Pencil
Module
Modeling
Module
Nodes & Physics
Module
Pipeline, Assets & IO
Module
Platforms, Builds & Tests
Module
Python API
Module
Render & Cycles
Module
Sculpt, Paint & Texture
Module
Triaging
Module
User Interface
Module
VFX & Video
Module
Viewport & EEVEE
Platform
FreeBSD
Platform
Linux
Platform
macOS
Platform
Windows
Severity
High
Severity
Low
Severity
Normal
Severity
Unbreak Now!
Status
Archived
Status
Confirmed
Status
Duplicate
Status
Needs Info from Developers
Status
Needs Information from User
Status
Needs Triage
Status
Resolved
Type
Bug
Type
Design
Type
Known Issue
Type
Patch
Type
Report
Type
To Do
No Milestone
No project
No Assignees
9 Participants
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: blender/blender#114958
Loading…
Reference in New Issue
Block a user
No description provided.
Delete Branch "Alaska/blender:metallic-bsdf"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Add Metallic BSDF Node to the shader editor.
This node can primarily be used to create more realistic looking
metallic materials than the existing Glossy BSDF node.
This commit does not add any new closures to Cycles, it simply exposes
existing closures that were previous hard to access on their own.
metallic component of the Principled BSDF. Results should match
between the Metallic BSDF and Principled BSDF when using the same
settings.
limited to custom OSL scripts. The Conductor frensel type accepts
IOR and Extinction co-efficents to define the appearance of the
material based off real life measurements.
EEVEE only supports the F82 fresnel type with internal code to convert
the the pyshical conductor inputs in to a colour format for F82,
which can lead to noticable rendering differences with
some configurations.
Images:
Node with the 2 fresnel types:
When using the same settings, the
F82 Tint
mode will produce the same result as a Metallic Principled BSDF.The
Physcial Conductor
fresnel option allows users to specifyn, k
(IOR and extinction) values for the conductor fresnel/ The main benefit this offers is that it allows people to taken, k
values from real life materials if material accuracy is important. A list containing somen, k
values can be found here: https://physicallybased.info/n, k
n, k
n, k
Intially when I mentioned adding this to Blender, it was going to be called the "Metallic BSDF". But I renamed it to the "Conductor BSDF" in line with MaterialX.
Please let me know if you want the name changed.
What is the difference between this and Glossy BSDF?
Generally this is good to have, but I think we should a) support the full range of Microfacet distributions and b) have an enum for switching between F82 Fresnel and the proper conductive Fresnel (which currently is only available through OSL), potentially also the Artist-Friendly Base/Edge Color reparametrization since enough other tools use it and it's quite straightforward to add without a new closure.
Is the OSL "proper conductive Fresnel"
osl_closure_conductor_bsdf_setup()
in/intern/cycles/kernel/osl/closures_setup.h
or is it something else?Sorry, it's not clear to me what you mean by this. Do you mean add an option to switch between a Base/Edge color input, and a
n, k
input? For both the F82 Fresnel and the Conductive Fresnel?I just wanted to add the commit message of one of the recent commits to explain recent changes.
Notable changes from previous revision of Conductor BSDF:
There are three "Fresnel Types" that can be selected on the node.
bsdf_microfacet_setup_fresnel_conductor()
in Cycles. Takes a ColorBase
andTint
input making it "artist friendly" compared to theConductor Fresnel
option (see below). Automatic code is run to turn these colors inton, k
values forfresnel_conductor
(which usesn, k
values).bsdf_microfacet_setup_fresnel_f82_tint()
in Cycles. Takes a Color "Base" and "Tint" input. This option should match a metallic Principled BSDF material.bsdf_microfacet_setup_fresnel_conductor()
in Cycles. Takesn, k
values as inputs.Base
andF82 tint
colors and uses them in the F82 tint formula. This causes rendering differences between EEVEE and Cycles.Various functions have been added to support the new
Conductor Fresnel - Artistic
.conductor_ior_from_color
andconductor_extinction_from_color
functions to getn, k
values from colorBase
andTint
inputs."Artist Friendly Metallic Fresnel", Ole Gulbrandsen, 2014
.artistic_ior
node.General other changes (E.G. Change names of certain inputs, adjust default values, etc.)
@LukasStockner, can you review this one?
@LukasStockner and @brecht , is there interest in adding a Conductor BSDF node? If so, should I rebase this against main?
I think it generally should still be the goal to have these components of the Principled BSDF available as individual nodes. So I think yes.
Agreed, this is definitely good to have (also for physically-based metallic thin film in the future). Sorry for letting this one slip through the cracks, I'll do a proper review soon.
I've merged main into this pull request and I've shifted the TODOs into the pull request message. The TODOs are there because I'm not sure how to resolve them, or how best to approach them.
@ -470,0 +478,4 @@
sd, sizeof(MicrofacetBsdf), rgb_to_spectrum(make_float3(mix_weight)));
if (!(bsdf == NULL)) {
uint base_ior_offest, edge_tint_k_offset, rotation_offset, tangent_offset;
Typo:
offest
.@ -0,0 +4,4 @@
vec4 fresnel_conductor(float cosi, const vec3 eta, const vec3 k)
{
const vec4 cosiv4 = vec4(cosi);
I'd rather perform this computation in
vec3
and then do@ -4045,6 +4045,29 @@ static const EnumPropertyItem node_ycc_items[] = {
{0, nullptr, 0, nullptr, nullptr},
};
static const EnumPropertyItem node_conductor_distrobution_items[] = {
Typo:
distrobution
.@ -4048,0 +4048,4 @@
static const EnumPropertyItem node_conductor_distrobution_items[] = {
{SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""},
{SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""},
{SHD_GLOSSY_MULTI_GGX,
Do we want to keep the Multi/Single GGX distinction here? I kept it in for compatibility, but since this is a new node, I'd prefer just having a single GGX option that enables it.
I'm not the right person to answer that question. Maybe Sergey or Weizhen can share their thoughts.
Hm, let's keep it for now, it's not too much complexity.
@ -4048,0 +4058,4 @@
};
static const EnumPropertyItem node_conductor_fresnel_type_items[] = {
{SHD_CONDUCTOR, "CONDUCTOR", 0, "Conductor Fresnel", ""},
Not a big fan of naming this the same as the node. Maybe something like "Physical" would make more sense.
Then again, I'd actually prefer naming the entire node "Metallic BSDF" and having the options "Physical Conductor", "Artistic Conductor" and "F82 Approximation".
Maybe "Physically accurate Fresnel effect based on the complex IOR of the material" as the description?
(apparently I can't create a second thread on the same line, so ignore the comment above).
@ -61,6 +61,7 @@ DefNode(ShaderNode, SH_NODE_ATTRIBUTE, def_sh_attribute, "ATT
DefNode(ShaderNode, SH_NODE_AMBIENT_OCCLUSION, def_sh_ambient_occlusion,"AMBIENT_OCCLUSION", AmbientOcclusion, "Ambient Occlusion", "Compute how much the hemisphere above the shading point is occluded, for example to add weathering effects to corners.\nNote: For Cycles, this may slow down renders significantly")
DefNode(ShaderNode, SH_NODE_BACKGROUND, 0, "BACKGROUND", Background, "Background", "Add background light emission.\nNote: This node should only be used for the world surface output")
DefNode(ShaderNode, SH_NODE_HOLDOUT, 0, "HOLDOUT", Holdout, "Holdout", "Create a \"hole\" in the image with zero alpha transparency, which is useful for compositing.\nNote: the holdout shader can only create alpha when transparency is enabled in the film settings")
DefNode(ShaderNode, SH_NODE_BSDF_CONDUCTOR, def_conductor, "BSDF_CONDUCTOR", BsdfConductor, "Conductor BSDF", "Reflection with microfacet distribution, used for materials such as metal or mirrors")
The description here appears to be identical to the Glossy BSDF, we might want to add something about specifically modeling the reflectivity of metals.
@ -0,0 +17,4 @@
.default_value({0.183f, 0.421f, 1.373f})
.min(0.0f)
.max(100.0f)
.description("PLACEHOLDER");
I'd say "Real part of the conductor's IOR" and "Complex part of the conductor's IOR". The entire purpose of this mode is for users who know what that is, I wouldn't worry about a simple intuitive explanation here (especially since there is none as far as I know).
@ -0,0 +84,4 @@
{
const int fresnel_method = node->custom2;
bke::nodeSetSocketAvailability(
Feels like we should do
const bool is_physical = (fresnel_method == SHD_CONDUCTOR);
and then use that instead of repeating it four times.Shader: Add Conductor BSDF Nodeto Shader: Add Metallic BSDF Node@ -4048,0 +4064,4 @@
0,
"Artistic Conductor",
"Conductor Fresnel with artist friendly color inputs"},
{SHD_CONDUCTOR_F82, "F82", 0, "F82 Approximation", ""},
Maybe "An approximation of the Conductor Fresnel curve based on the perpendicular color and the tint at an angle of 82°, also used by the Principled BSDF" as a description?
Also, thinking about it some more, I'm not that happy with "F82 Approximation" as a UI name anymore, it seems too technical. I can't really come up with anything better though, so I'm open to suggestions.
What about
F82 Tint
? OrF82 Conductor Tint
?I'd specifically avoid "Conductor" since it's not using the actual conductor Fresnel term, unlike the other two.
"F82-Tint" is the name I've seen others use for this model, so yeah, I guess that would be fine.
@ -0,0 +109,4 @@
/* TODO: Figure out how to switch between artisitic_ior and using
* the IOR and Extinction values directly.
* `node` is not defined here so we can't use `node->custom2` */
Based on
node_parser.h
, I thinknode_
should work?Looks like e.g.
node_shader_clamp.cc
is using it.What's your thoughts on using Gold as the default IOR and Extinction values? (These are the default values I am currently using)
It's different from what is usually done (A white or light grey material). I could swap it for Aluminium, or a made up material like:
IOR: 3.0
Extinction: 3.0
It's white/light grey in appearance, the IOR and Extinction are constant simple numbers, and it shows that the IOR and Extinction can and usually are higher than 1.0
I think Gold is fine - the two things I'd like the default to have are a) a noticeable tint to show the advantage of this model vs. classic Glossy and b) no noticeable oxide layers in its common form to avoid the "but it doesn't look like that in real life" issue (notably, this applies to copper). Gold matches both of these.
One thought: If we use a specific metal as the default, we might also want set the color inputs accordingly. However, since they are shared, we can only set them correctly for one mode.
Also, after checking my old F82 spectral fits, turns out that Gold is not an ideal pick - it's too saturated for sRGB and doesn't actually have a strong tint effect.
Based on the data there, maybe Titanium or Chromium? I can't find hard data on oxide layer impact on appearance, but I'd say that the bulk material looks close enough to what I'd expect it to look like (unlike e.g. copper). That would also be a more neutral default.
I assume this pull request is nearing the end of development. So I've created some files that can be added to the render test suite. In the zip archieve there are 5 .blend files. Here's an explaination of each and what they test.
metallic_beckmann_physical
- Test the bechmann microfacet distrobution with the physical conductor. This is to ensure the setting is working, and it interacts with the physical conductor in an alright manner.metallic_ggx_physical
- Test the GGX microfacet distrobution with the physical conductor. This is to ensure the setting is working, and it interacts with the physical conductor in an alright manner.metallic_multiggx_artistic
- Primarily testing the artist friendly reparemterization of the physical conductor.metallic_multiggx_f82
- Primarily testing that the F82 tint and making sure it works.metallic_multiggx_physical
- Test the Multiscatter GGX microfacet distrobution with the physical conductor. This is to ensure the setting is working, and it interacts with the physical conductor in an alright manner.Each test contains 4 spheres with different colours, roughness, and anisotropy.
The main light source in the scene is large and has multi-importance sampling left on (requested as part of #123012
Enable MIS on light in some tests
).The only major configurations that I can identify are missing are
beckmann
andggx
with F82, just to ensure they interact nicely. But that's probably not neccesary.Pretty much LGTM now, just two small notes.
The tests also look good, I don't think we need the other two combinations.
@ -105,1 +105,4 @@
ccl_device float3 conductor_ior_from_color(float3 r, const float3 edge_tint)
{
r = clamp(r, zero_float3(), make_float3(0.99));
This needs to be
0.99f
, otherwise the compiler complains. Same in the function below.@ -0,0 +11,4 @@
static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Color>("Base Color").default_value({1.0f, 1.0f, 1.0f, 1.0f});
Should probably be
0.8f, 0.8f, 0.8f, 1.0f
for consistency.@LukasStockner what other tools use this parametrization? I thought Naty Hoffman argued that this model is not really artist-friendly, that's why we decided to use the Adobe F82 model? gITF seems to have decided against it, OpenPBR only mentioned it in the thin-film iridescence section.
@Alaska the list you provided does not contain
n, k
values for RGB, for me thePhysical Conductor
mode is quite hard to use. I think we can provide a list of common metals and theirn(r, g, b), k(r, g, b)
and put them in the manual. I'm not sure which algorithm you used to derive those values, or if there are better methods. Probably we can also add this link: https://refractiveindex.info@ -106,0 +133,4 @@
ccl_private float3 *eta,
ccl_private float3 *k)
{
/* Equations from "Artist Friendly Metallic Fresnel", Ole Gulbrandsen, 2014
I think it's better to put this comment above
conductor_ior_from_color()
and addEquations to map color to complex IOR, from "Artist...
@ -482,0 +516,4 @@
bsdf->alpha_y = alpha_y;
ClosureType distribution = (ClosureType)node.w;
/* setup bsdf */
Setup BSDF.
@ -349,1 +349,4 @@
ccl_device_inline float3 mix(const float3 a, const float3 b, float3 t)
{
return make_float3(mix(a.x, b.x, t.x), mix(a.y, b.y, t.y), mix(a.z, b.z, t.z));
a + t * (b - a)
should be better than element-wise.@ -4091,0 +4105,4 @@
"PHYSICAL_CONDUCTOR",
0,
"Physical Conductor",
"Physically accurate Fresnel effect based on the complex IOR of the material"},
Not sure if we can call an RGB approximation of complex IOR physically-accurate, I bet it's going to look quite different compared to full-wavelength.
Maybe something like "Fresnel conductor based on the complex refractive index per color channel"?
@ -4091,0 +4110,4 @@
"ARTISTIC_CONDUCTOR",
0,
"Artistic Conductor",
"Conductor Fresnel with artist friendly color inputs"},
Fresnel conductor
@ -4091,0 +4115,4 @@
"F82",
0,
"F82 Tint",
"An approximation of the Conductor Fresnel curve based on the perpendicular color and the "
conductor (lower case)
I don't think "perpendicular color" is understandable enough or a standard term. We can say
colors at perpendicular and glancing (roughly 82°) angles
.@ -0,0 +11,4 @@
static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Color>("Base Color").default_value({0.8f, 0.8f, 0.8f, 1.0f});
The
Base Color
andEdge Tint
should also default to Titanium. Maybe we can try on F82 Tint and hope the Artistic Conductor does not look too different.I could of explained it better. If you go to https://physicallybased.info/ then in the top left change the engine to something like
Corona
, then most of the metals will haven, k
values when you expand their information.Ah, that seems better. Still wondering how they obtained the numbers though, whether it's just reading 3 specific wavelengths which they decide to represent RGB. That won't be very accurate.
When I added the
n, k
values to https://api.physicallybased.info/ I was indeed using 3 specific wavelengths (0.45, 0.55, 0.65), which I know isn't ideal, but it was the only method I knew of at the moment.It's on my todo list to update them to more accurate values with the help of this script from @LukasStockner #99447 (comment)
or this one from Naty Hoffman: https://github.com/natyh/material-params
The database is open source, so it's also possible to just add the updated values yourself (as a PR) if you prefer that: https://github.com/AntonPalmqvist/physically-based-api
In the recent meeting notes, it was suggested to remove the
Artistic Conductor
option until Lukas was back and ideas could be discussed with them.Should I remove it now? Or keep it in for the meantime?
@AntonPalmqvist thank you for the info! I tried Lukas' curve fitting and got the following result for Titanium:
Visually they look quite close to me, I think we can use these as default values for now. Probably we should use illuminant D65 instead, but it doesn't need to be part of this PR to use optimal values. I can make a PR in https://github.com/AntonPalmqvist/physically-based-api if I get some comparison with groundtruth values, thank you for the suggestion @AntonPalmqvist.
@ -0,0 +12,4 @@
static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Color>("Base Color").default_value({0.8f, 0.8f, 0.8f, 1.0f});
b.add_input<decl::Color>("Edge Tint").default_value({1.0f, 1.0f, 1.0f, 1.0f});
We need description for other sockets too. Mostly you can copy from Principled BSDF, for Base Color and Edge Color you can say "Color at perpendicular angle" and "Color at glancing angle (roughly 82°)".
@ -0,0 +17,4 @@
.default_value({2.741f, 2.542f, 2.267f})
.min(0.0f)
.max(100.0f)
.description("Real part of the conductor's IOR");
I would prefer not to use abbreviations in the description if possible. You can say "Real part of the conductor's refractive index, often called n".
@ -0,0 +22,4 @@
.default_value({3.814f, 3.434f, 3.038f})
.min(0.0f)
.max(100.0f)
.description("Complex part of the conductor's IOR");
"Imaginary part of the conductor's refractive index, often called k"
I wonder if we should just call the n and k? Might be more well-known than IOR and Extincition, but I'm not sure.
@Alaska yes it would be nice if you remove Artistic Conductor for now. The goal is to get this in main as soon as possible to deal with issues that might come up later. Sorry for the extra work.
If it's indeed necessary for compatibility or whatever reason, we can add this mode back at any time, but for me it is doing a pretty similar job as F82-tint, just less artist-friendly and might cause confusion if we have both.
Here are updated test files (The F82 tests had a undefined fresnel type, so I fixed that. All the other files are the same, with the exception of the artistic fresnel test which was removed).
I would prefer
F82 Tint
to be the default because it's easier to use.@ -0,0 +28,4 @@
.min(0.0f)
.max(100.0f)
.description("Imaginary part of the conductor's refractive index, often called k");
b.add_input<decl::Float>("Roughness")
The description of Roughness, Anisotropy, Rotation and Tangent is still missing.
Looks good now, thanks! Sergey said he still wants to look at this PR, let's see if he has the time.
And because it touchs EEVEE I'll also tag Clément to have a look.
@ -0,0 +4,4 @@
vec3 fresnel_conductor(float cosi, const vec3 eta, const vec3 k)
{
const vec3 cosiv3 = vec3(cosi);
const
have different meaning in GLSL. It is equivalent toconstexpr
. So remove it from everywhere in this function as well for its parameters.@ -0,0 +11,4 @@
const vec3 tmp_f = (eta * eta) + (k * k);
const vec3 tmp = tmp_f * cosi_sqr;
const vec3 Rparl2 = (tmp - (2.0 * eta * cosiv3) + one) / (tmp + (2.0 * eta * cosiv3) + one);
Can't this
2.0 * eta * cosiv3
be stored in a tmp variable?Some minor feedback on the code. Other than that I think the PR is ready.
I've checked performance on M2 Ultra, and there was no performance impact. Surely this doesn't mean there is no impact on all compute backends, but at least something :)
@ -482,0 +488,4 @@
ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc(
sd, sizeof(MicrofacetBsdf), rgb_to_spectrum(make_float3(mix_weight)));
if (!(bsdf == NULL)) {
Something cosmetic, but I think
if (bsdf != NULL) {
reads easier.@ -2444,0 +2445,4 @@
NODE_DEFINE(MetallicBsdfNode)
{
NodeType *type = NodeType::add("Metallic_bsdf", create, NodeType::SHADER);
Node types are lower case, so
metallic_bsdf
Thanks!
Question about the initial post and link. It's is states that the link contains n,k values. I only see rgb values for base and specular color?
You can see the n, k values either by switching the IOR dropdown to Complex IOR, or by setting the engine to one that supports n,k values, such as RenderMan, from the Engine dropdown.
@AntonPalmqvist
Ah now I see. I was looking at this on mobile, in mobile view we don't see those other columns. So I was a bit confused. If switch to desktop view in mobile browser they do appear.
Thanks for clearing that up
See attached, mobile view vs desktop view on mobile