Cycles: Rework Principled BSDF Clearcoat #110993
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
6 Participants
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: blender/blender#110993
Loading…
Reference in New Issue
Block a user
No description provided.
Delete Branch "LukasStockner/blender:clearcoat-principled"
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?
This is probably unintentional so that's why I'm reporting it.
Changing the
Coat Tint
colour while the coat parameter is set to0
still has an impact on the material.@ -209,3 +203,2 @@
ccl_private PrincipledDiffuseBsdf *bsdf = (ccl_private PrincipledDiffuseBsdf *)bsdf_alloc(
sd, sizeof(PrincipledDiffuseBsdf), diff_weight);
if (coat_tint != one_float3()) {
Replacing
if (coat_tint != one_float3())
withif (!isequal(coat_tint, one_float3()))
fixes compilation issues with the Metal backend.For reference, the compilation issue is this:
The changes and implementation look fine besides the issues mentioned by @Alaska.
When this gets committed, add-ons will need to be updated too. I think it's just atomic and glTF that are affected. So I'll just ping @Blendphys @JulienDuroure here so they know this is coming.
This is currently intentional. The intention is that the Coat input controls the strength of the specular reflection on the interface, while the Tint input controls the strength of the absorption in the volume of the layer.
In the future, we might want to introduce a Coat IOR control (as in OpenPBR) to control the specular intensity. In this case, the Coat input would act as a "is a Coat layer present?" input, and in that case it should indeed also control the tint.
I haven't done this yet since, to do it properly, the Coat IOR should affect the Fresnel or the "main" specular reflection.
However, now that I think about it we might want to:
*0.25
term in versioning (IOR 1.2 has a reflectivity that is roughly one quarter of IOR 1.5)a42da79bc1
toca6de1282d
That sounds good.
ca6de1282d
to2771d57ae2
One remaining detail: When creating a new file, it appears that the versioning code runs, since the initial
Material
ends up with an IOR of 1.2. Not sure how to avoid this, just bump the default file to a newer version?Also, note for landing this: Two tests (
principled coat
andprincipled bsdf interior
) fail and need to be updated. For the first one, we should to update the test file to turn on MIS on the lamp to get more than a few fireflies for the highlight.WIP: Cycles: Rework Principled BSDF Clearcoatto Cycles: Rework Principled BSDF ClearcoatRunning a quick test, I can identify a few issues.
Blender crashes when using EEVEE with this pull request on the Metal backend for Blender (Tested with a M1 Pro). I haven't done much debugging on the Metal EEVEE side so I might be wrong about this, but error messages suggests it is a similar issue as before.
'coat_tint.rgb != vec3(1.0)' vector of 3 'bool' values is not contextually convertible to 'bool'
. Note: Cycles Metal does compile and work. EEVEE with OpenGL (like on Windows or Linux) doesn't crash.There is a mismatch between Cycles SVM and Cycles OSL when the coat IOR is below 1.0. Cycles SVM behaves like Coat IOR is 1.0. Cycles with OSL kind of behaves like the selected IOR and shows a Total Internal Reflection like effect, but is also a bit broken if I understand my physics correctly.
The EEVEE material needs to be updated to match Cycles. At the moment it doesn't match (Tested on Windows with a Nvidia GPU). This is most noticeable when the coat tint has a strong colour, but coat is set low (or to 0). It's like the EEVEE implementation hasn't been updated with the recent changes?
@ -67,6 +69,12 @@ void node_bsdf_principled(vec4 base_color,
vec3 base_color_tint = tint_from_color(base_color.rgb);
if (coat_tint.rgb != vec3(1.0)) {
This results in Blender crashing on the Metal backend for Blender/EEVEE. You can find the error message below.
'coat_tint.rgb != vec3(1.0)' vector of 3 'bool' values is not contextually convertible to 'bool'
Thanks, should be fixed now I think?
Defaults in the startup.blend can be changed in
source/blender/blenloader/intern/versioning_defaults.cc
. It's generally preferred to do that over updating thestartup.blend
for every template, since there is some risk in that.I also noticed a weird behavior with certain coat colours and device configurations.
If the coat tint has a blue channel set to 0, and you're rendering with the CPU, then the coat will appear overly dark.
If you are rendering with a GPU or the blue channel is not set to 0, this issue does not occur. I have attached a video demonstrating the issue.
I tested this on and can reproduce this behavior on:
Steps to reproduce:
RGB(1.0, 1.0, 0.0)
@ -101,0 +98,4 @@
.subtype(PROP_FACTOR)
.description(
"Controls the intensity of the coat layer, both the reflection and the tinting. "
"Typically should be zero or one for physically-based materials.");
Remove the full stop from the end of
"Typically should be zero or one for physically-based materials."
. The Blender UI automatically adds a full stop to the end.Thanks for the review!
This should work now I think, could you please test again?
Fixed, thanks. IOR is forced to be >1 here since it's a coating. IOR<1 in general is a hack for modeling nested dielectrics currently, I still hope to get proper support for this in the future.
Fixed, thanks.
Can reproduce, this is weird. I'll try to find the issue.
Perfect, thanks! I'll have a look.
@blender-bot package
Package build started. Download here when ready.
Looks fine to me assuming GPU build passes on all platforms and the comment is addressed.
@ -38,2 +38,2 @@
static const pxr::TfToken clearcoat("clearcoat", pxr::TfToken::Immortal);
static const pxr::TfToken clearcoatRoughness("clearcoatRoughness", pxr::TfToken::Immortal);
static const pxr::TfToken coat("coat", pxr::TfToken::Immortal);
static const pxr::TfToken coatRoughness("coatRoughness", pxr::TfToken::Immortal);
These should not be renamed.
There's still a mismatch between Cycles SVM, Cycles OSL, and EEVEE.
When the coat IOR is below or at 1.0, all three behave differently.
Other than that, many of the previous issues have been addressed. Metal EEVEE and Cycles compiles and work just fine. EEVEE now more closely matches Cycles (with the exception of the IOR = 1.0 edge case). CPU and GPU now match in Cycles with the blue=0 issue being fixed.
@ -104,0 +109,4 @@
if (Coat > 1e-5) {
float coat_r2 = CoatRoughness * CoatRoughness;
closure color CoatBSDF = dielectric_bsdf(
CoatNormal, vector(0.0), color(1.0), color(0.0), coat_r2, coat_r2, CoatIOR, "ggx");
The
CoatIOR
inclosure color CoatBSDF = dielectric_bsdf(CoatNormal, vector(0.0), color(1.0), color(0.0), coat_r2, coat_r2, CoatIOR, "ggx");
also needs to be set tomax(CoatIOR, 1.0)
to avoid inconsistencies when compared to Cycles SVM when theCoatIOR
is below 1.0.@ -106,0 +109,4 @@
#define SOCK_COAT_ROUGHNESS_ID 16
b.add_input<decl::Float>("Coat IOR")
.default_value(1.5f)
.min(0.0f)
If CoatIORs below 1.0 aren't supported at this time, then I would personally like see to min IOR set to 1.0.
Thanks for checking again - I've applied the OSL fix and limited the input to a minimum of 1.0 now. I'm not really sure what you mean with the EEVEE issue, though - I don't see anything obviously weird.
@ -481,15 +481,12 @@ void USDMaterialReader::set_principled_node_inputs(bNode *principled,
set_node_input(roughness_input, principled, "Roughness", ntree, column, &context);
}
if (pxr::UsdShadeInput clearcoat_input = usd_shader.GetInput(usdtokens::clearcoat)) {
I'm getting build errors here. Seems to be because you updated the names earlier in
96b362cac7
but didn't update them here.Ah, I was building with USD disabled. I'll fix it, thanks.
Either I was testing it incorrectly, or it was fixed by recent changes/merges with main. I see no obvious issues with EEVEE now.
I rewrote EEVEE principled BSDF #111754, and adjusted the part in this pull request so that it uses coat IOR instead of the default 1.5 in the merge commit
445464e5f2
Looks good to me assuming those USD tokens giving build errors are updated to be clearcoat instead of coat.
Fantastic, thanks!
How is the tint change actually done. In other renderers they sometimes have a setting for weight or clear coat thickness. This will influence how much the tint effects the final color.
Today in blender today, someone pointed out. That in 4.1 branch, the material out has a attribute called thickness. There is no documentation yet. Is this attribute related to coat settings?
At the moment, the coat layer has a thickness of "1 absorption distance" (This isn't a physical unit, it's a mathematical thing to apply the tint properly). And how much tint is applied is based on the "optical depth" (depending on how a ray enters a material, it might travel straight through the coat, or through the coat at a angle, if it travels through at an angle, it will travel further than straight through, increasing the "optical depth"). Along with the optical depth, the
Coat Weight
will increase or decrease the amount of tinting being applied.The
Thickness
setting on the material output node is unrelated to Coat Tint. Based on what I understand, this is probably related to theRefraction Depth
and other depth settings used by EEVEE.@Alaska thanks for the reply
Wonder why don't add coat thickness then. I mean they added color for it and use the thickness, but have added a hardcoded value as it seems. An old renderer I use did have custom weighting, was really nice feature. Specially on woods and car paints
@RomboutVersluijs I don't know exactly why a thickness option wasn't added. Maybe it was to align with another material standard (OpenPBR/Standard surface)? Maybe it was for other reasons. You will need to wait for a response from Brecht and/or Lukas to get the exact reasoning.
Note: Discussion about features added to the Principled BSDF in 4.0+ should probably happen over on devtalk in the feedback thread for the Pricinipled BSDF: https://devtalk.blender.org/t/principled-v2-feedback-discussion-thread/24997
Im not sure how much he is involved with the adjustments. To my understanding it's Lucas stocker doing the work. He also did a bcon presentation on it last year. I'm very hyped for all the work he has and is doing
Coat Thickness is one of the many options that could theoretically be added, but in practice it's always a balancing act between supporting more use cases vs. keeping the node manageable.
In this case, thickness can easily be implemented manually with a Power node (as in, set the Tint input to
pow(original tint, thickness)
), so I don't think having it as an option directly in the Principled BSDF really adds much.Side note: Coat Weight effectively was a thickness input before #113468.
@LukasStockner but how is the tint than controlled if it's occupied by the power input?
@RomboutVersluijs , the node setup Lukas is referring too likely looks like this:
Adjust the Coat Tint and Thickness values on the left to get the color and thickness you want.
Note: For ideal results, only use this node setup in combination with a
Coat Weight
of 1. And until #113468 is merged in Blender/Cycles, you may get "unexpected results" with this setup with a Coat Wight set to anything other than 0 or 1.@Alaska can I ask why the color is separated per component and then gets the power exponent. Is that because the method cannot handle the color at once, meaning a non separated color. Guess it's single value only, hence the color of the socket
Yes, the Math node only handles single number inputs. Which means that when you plug a Color input into it (Which is three numbers: Red, Green, Blue), it will be reduced to a single number, have the math applied to it, then output as a single number. This means we lose our color information if we pass a color input straight through a math node.
To get the desired result, we have to separate the individual color channels and apply the power to each color channel separately.
Note: You don't have to do this for all math operations you want to apply to the color input. The
Mix RGB
node supports various mathematical operations you can apply to color inputs. It just doesn't supportpower
, which is required for this use case.@alaska sorry for the questions. But was does power actually do in this setup. How is it different vs boosting the color itself. I mean if the color component is multiplied by a certain number, is it the same as make the color values higher and thus more towards white?
The power node in this setup will increase the saturation in some situations and decrease the brightness of the coat as the "thickness" input is increased. This simulates the properties of a thicker coat (which absorbs more light as a result of light passing through more material).
Color values are typically in the range of [0..1]. As a result, it's likely your color will be something like this (Red: 0.3, Green: 0.8, Blue: 0.9). When you take a value less than 1, and raise it to the power of anything greater than 1, the output value will be lower than the input, which creates the "decreased brightness effect". The increased saturation effect comes from the non-linear relationship between input and output when working with powers, and the fact we're applying this operation to three different values (Red, Green, Blue). This is why it's different from just boosting the color until you reach white.
Example showing why using power can decrease the brightness:
Note: If you want to use this method to add coat thickness to your materials, make sure your Red, Green, and Blue channels are all greater than 0, and less than 1, and avoid using thickness values less than 1. The RGB nature of Cycles and approximations in this thickness "simulation" make these two cases behave a bit weird. I should of mentioned this earlier.
@Alaska thanks for the very clear and concise explanation. I understand now. I was thinking to simple of this. Now it makes sense