Skip to content

Add sheen shading support - #111568

Open
LiveTrower wants to merge 1 commit into
godotengine:masterfrom
LiveTrower:sheen-shading
Open

Add sheen shading support#111568
LiveTrower wants to merge 1 commit into
godotengine:masterfrom
LiveTrower:sheen-shading

Conversation

@LiveTrower

@LiveTrower LiveTrower commented Oct 12, 2025

Copy link
Copy Markdown
Contributor

Part of godotengine/godot-proposals#1934

This PR adds support for sheen shading, which allows for the easier and more realistic creation of cloth materials like cotton, velvet, silk, etc.

It only has 3 inputs:

  • SHEEN: to control the intensity of the effect.
  • SHEEN_ROUGHNESS: to adjust the level of roughness or glossiness.
  • SHEEN_COLOR: to change the specular reflectance color.

In the StandardMaterial3D, you can place a texture with the following information:

  • R (Red channel): A mask to indicate which parts are cloth and which parts are not.
  • G (Green channel): A roughness map to provide variations in reflections.

Here are some usage examples so you can see how it looks.

Cloth Ball Sweater(cotton)
cloth sweater
Dress(silk) Chair(velvet)
dress chair

⚠️ Important notes ⚠️

artifacts(white) artifacts(red)

I haven't taken the time to report it, nor do I know how it can be solved.

@clayjohn

Copy link
Copy Markdown
Member

Doesn't Filament's implementation of sheen basically duplicate our implementation of rim lighting?

@LiveTrower

Copy link
Copy Markdown
Contributor Author

Doesn't Filament's implementation of sheen basically duplicate our implementation of rim lighting?

No, because unlike rim, sheen is more standard and is PBR, which provides more accurate results and is absolutely necessary for godotengine/godot-proposals#1934.

We could categorize it as a replacement and deprecate rim, but rim would still be ideal for mobile renders and compatibility since, as I mentioned, the sheen effect wouldn't be available due to the lack of the SheenLUT in those renders. Although there's a possibility of making an analytical approximation of the Sheen LUT, as is already done with the BRDF LUT, but I don't have the knowledge of how that's done.

@BlueCube3310

Copy link
Copy Markdown
Contributor

Comparison between sheen and rim lighting: sheen

@fire

fire commented Oct 13, 2025

Copy link
Copy Markdown
Member

How difficult is it to add to mobile? I am a part of V-Sekai development community focuses on providing social VR functionality for the open source Godot Engine.

The current mobile render is the one that is recommended for virtual reality headsets that run on android os.

@LiveTrower

LiveTrower commented Oct 13, 2025

Copy link
Copy Markdown
Contributor Author

@fire The problem is the IBL part, since it requires a Sheen LUT and this is calculated in integrate_dfg.glsl, but this is only available in Forward+ because for mobile and compatibility, it was decided to continue using an analytical approximation of the BRDF(see) to avoid having to read the DFG LUT texture, as far as I know, most mobile devices struggle with texture reads.

So, as I mentioned, there might be a possibility of making an analytical approximation with the Sheen LUT, but I don't know how to do that.

@fire

fire commented Oct 13, 2025

Copy link
Copy Markdown
Member

@allenwp Has had some experience doing that for the color tone mapping etc enhancements. I'll ask.

@allenwp

allenwp commented Oct 14, 2025

Copy link
Copy Markdown
Contributor

I've used both Mathematica and Excel to make polynomial approximations. But Mathematica's NonlinearModelFit can sometimes be useful as well, as you get to specify the output function and parameters that you want fitted to the source data. I expect this wouldn't be useful for this case, though, so probably a basic polynomial regression is the best bet?

@fire

fire commented Oct 18, 2025

Copy link
Copy Markdown
Member

@LiveTrower Can you post the buffer of floats you want us to curve fit?

@LiveTrower

Copy link
Copy Markdown
Contributor Author

@LiveTrower Can you post the buffer of floats you want us to curve fit?

I don't know if this is what you want, but I'm leaving you a zip file with a Python script to read the DFG LUT and extract the values from the blue channel, which is where the Sheen LUT is located.

dds_values.zip

@fire

fire commented Oct 21, 2025

Copy link
Copy Markdown
Member

@LiveTrower Here's an CHOP-coded approximation https://github.com/fire/godot-sheen-look-up-table

I'm not sure how low the mean error we should attempt, feel free to experiment.

Suggest playing with the degree variable. https://github.com/fire/godot-sheen-look-up-table/blob/26b7afd775177f1dbbd2956d99af2da2b04307b7/main.py#L21

Edited:

Updated the readme. Was previously describing a rational function, but moved back to polynomial.

Edited:

Interesting results at deg 0, deg 1, deg 4, and deg 8.

dds_values> uv run python .\main.py
Approximated analytical expression for the sheen LUT:
0.0664957578919711
Mean Squared Error: 0.01711980566830958
dds_values> uv run python .\main.py
Approximated analytical expression for the sheen LUT:
-0.25030720970041*cos_theta + 0.180297312733505*r + 0.101500706375423
Mean Squared Error: 0.009064854351581322
godot-sheen-look-up-table> uv run python .\main.py
Approximated analytical expression for the sheen LUT:
-2.8418752634654*cos_theta**4 - 0.0752492803140749*cos_theta**3*r + 5.79787608128554*cos_theta**3 + 2.48562696566899*cos_theta**2*r**2 - 1.00253162077076*cos_theta**2*r - 3.65901503993457*cos_theta**2 + 0.276146452617512*cos_theta*r**3 - 3.8030419846424*cos_theta*r**2 + 1.42331784042998*cos_theta*r + 0.658695894178778*cos_theta - 0.823548193452199*r**4 + 1.35743804092077*r**3 + 0.430920102235383*r**2 - 0.224877093447145*r + 0.0132743926195602
Mean Squared Error: 0.002395069535344717
dds_values> uv run python .\main.py
Approximated analytical expression for the sheen LUT:
-557.091779271558*cos_theta**8 + 464.017389846217*cos_theta**7*r + 2152.1266164332*cos_theta**7 - 230.321684192249*cos_theta**6*r**2 - 1525.96376250796*cos_theta**6*r - 3384.23333420742*cos_theta**6 + 2.86174085877387*cos_theta**5*r**3 + 744.890840615195*cos_theta**5*r**2 + 1932.42802940127*cos_theta**5*r + 2787.74835270357*cos_theta**5 + 104.289164776309*cos_theta**4*r**4 - 194.098783820854*cos_theta**4*r**3 - 825.798219330147*cos_theta**4*r**2 - 1189.47390170691*cos_theta**4*r - 1289.70446461101*cos_theta**4 + 16.4307961138826*cos_theta**3*r**5 - 264.236227330607*cos_theta**3*r**4 + 435.698733067964*cos_theta**3*r**3 + 330.115180358558*cos_theta**3*r**2 + 377.760815347863*cos_theta**3*r + 333.246911023428*cos_theta**3 - 33.7673457364751*cos_theta**2*r**6 + 56.2723698949418*cos_theta**2*r**5 + 148.016374822698*cos_theta**2*r**4 - 297.359389044023*cos_theta**2*r**3 - 3.59259176216401*cos_theta**2*r**2 - 64.9201817967158*cos_theta**2*r - 44.5916577589042*cos_theta**2 - 12.0589143469186*cos_theta*r**7 + 79.3217215327783*cos_theta*r**6 - 133.214050066957*cos_theta*r**5 + 45.9217563239256*cos_theta*r**4 + 45.1941989068905*cos_theta*r**3 - 14.9524287804133*cos_theta*r**2 + 6.30200063105549*cos_theta*r + 2.44540720268555*cos_theta + 8.53860911397782*r**8 - 24.68454951197*r**7 + 15.367948662591*r**6 + 11.3701055151527*r**5 - 13.5672939003094*r**4 + 2.94229103229011*r**3 + 0.453115385148636*r**2 - 0.128715903958555*r - 0.00103032751274113
Mean Squared Error: 0.0009670587699536178

@LiveTrower

Copy link
Copy Markdown
Contributor Author

@fire I apologize as the script and data I gave you are not for the Sheen LUT because the script doesn't correctly read the blue channel. To fix the problem, I decided it was better to simplify everything, so I separated the DFG LUT from the Sheen LUT and created another, simpler script that extracts the data.

Please also make sure to check that the approximation at least minimally resembles the original.
dds_values.zip

@LiveTrower

LiveTrower commented Oct 21, 2025

Copy link
Copy Markdown
Contributor Author

It seems this is going to be more complicated than I thought, since a value of 22 or 23 is needed for 'deg' which results in an error of 0.0010483543733100147 in the case of 22 and 0.0009242407786030217 with 23. But the formula becomes a monstrosity, so I don't know if this is actually good.

@fire

fire commented Oct 21, 2025

Copy link
Copy Markdown
Member

I tried rational functions, which has more power. Will try that.

Edited: Update the repo to use rational functions.

@LiveTrower

Copy link
Copy Markdown
Contributor Author

Here are some comparisons
Result
I'll test how it looks in action later, but I feel like it's going to cause some problems.

@fire

fire commented Oct 21, 2025

Copy link
Copy Markdown
Member

My friend said that MSE is not good enough for color. I'll pick another function.

Also, for some reason I was approximating the wrong LUT. Will investigate.

Edited:

Have to put this down for a long while. Thanks for investigating.

@QbieShay

Copy link
Copy Markdown
Contributor

Do we know how other engines deal with this?

@LiveTrower
LiveTrower requested a review from a team as a code owner March 17, 2026 16:06
@fire

fire commented Mar 17, 2026

Copy link
Copy Markdown
Member

If you can get the github actions passing we can try the artifacts.

@fire

fire commented Jun 18, 2026

Copy link
Copy Markdown
Member
matrix_2x2

I've been working on this @LiveTrower briefly.

@fire

fire commented Jun 18, 2026

Copy link
Copy Markdown
Member

After playing with trying to fit a glsl equation into sheen and failing, I would recommend that you c encode a texture for now.

@fire

fire commented Jun 22, 2026

Copy link
Copy Markdown
Member

My friend sent me this @JosephCatrambone . I haven't looked at it fully yet.

approximation

approximate_image.ipynb

@LiveTrower

Copy link
Copy Markdown
Contributor Author

My friend sent me this @JosephCatrambone . I haven't looked at it fully yet.

approximation [approximate_image.ipynb](https://github.com/user-attachments/files/29223885/approximate_image.ipynb)

To be honest, I have no idea how to use this. I used Google Colab to run the file, but I see that a PNG (which is the LUT) is used as an input, and a PNG is saved as an output, which would be the approximation. However, I don't see an equation that can be used in GLSL.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants