1+
2+
3+ #ifndef PI
4+ #define PI 3.1415926535897932384626433832795
5+ #endif
6+ #ifndef EPSILON
7+ #define EPSILON 0.001
8+ #endif
9+
10+ struct DisneyBSSDF {
11+ vec3 albedo;
12+ float opacity;
13+ vec3 normal;
14+ float mask;
15+ float thickness;
16+ vec3 scatteringDistance;
17+ // float roughness;
18+ // float ao;
19+ };
20+
21+ struct DisneyBSSDFSettings {
22+ int sampleCount;
23+ float worldUnitScale;
24+ float frameCounter;
25+ float testScene;
26+ vec2 samples[32 ];
27+ };
28+
29+
30+
31+ float random(vec2 st) {
32+ return fract (sin (dot (st.xy, vec2 (12.9898 , 78.233 ))) * 43758.5453123 );
33+ }
34+
35+ vec3 Rr(vec3 d, float radius) // Diffusion profile computation
36+ {
37+ return (exp (- radius / d) + exp (- radius / (d * 3.0 ))) / (8.0 * PI * d);
38+ }
39+
40+ float Pr(float d, float radius) // Diffusion profile PDF computation
41+ {
42+ return (exp (- radius / d) + exp (- radius / (d * 3.0 ))) / (8.0 * PI * d);
43+ }
44+
45+ vec3 evalDisneyBSSDF(
46+ vec3 viewPos,
47+ vec3 modelPos,
48+ vec3 radiance,
49+ vec2 uv,
50+ float camDist,
51+ sampler2D texturePosition,
52+ sampler2D textureDiffuseLight,
53+ sampler2D textureDiffuseBackLight,
54+ DisneyBSSDF bsdf,
55+ DisneyBSSDFSettings settings
56+ ) {
57+
58+ const float EPS = 0.0001 ;
59+
60+ // SETTINGS
61+ const int sampleCount = 4 ;
62+ const float worldUnitScale = 1.0 ;
63+ const float frameCounter = 5.0 ;
64+ const float testScene = 5.0 ;
65+ const float attenuationCoeff = 2.5 ; // The parameter to fit for single scatter
66+ const float blushScale = 0.4 ;
67+
68+ vec3 sssDiffuse = vec3 (0.0 );
69+ vec3 diffusion = vec3 (0.0 );
70+ vec3 weight = vec3 (0.0 );
71+
72+ // Diffuse Term
73+ vec3 diffuse = bsdf.albedo * texture(textureDiffuseLight, uv).rgb;
74+
75+ // Render world scale & distance LOD for scattering distance
76+ float distAttFactor = 1.0 / pow (camDist + EPS, 2.0 );
77+ vec3 d = clamp (mix (bsdf.scatteringDistance * worldUnitScale * camDist * distAttFactor, bsdf.scatteringDistance * worldUnitScale, testScene), EPS, 1.0 );
78+ float maxRadius = max (d.r, max (d.g, d.b));
79+
80+ // World fragment depth computation
81+ float depth = texture(texturePosition, uv).a;
82+ // vec2 fragCoords = uv * 2.0 - vec2(1.0);
83+ // vec3 fragViewPosition = (invProjection * (depth * vec4(fragCoords, 0.0, 1.0))).xyz;
84+ // vec3 fragWorldPosition = (invView * vec4(fragViewPosition, 1.0)).xyz;
85+ vec3 fragViewPosition = viewPos;
86+ vec3 fragWorldPosition = modelPos;
87+
88+ // To avoid periodic pattern sampling
89+ float jitter = 2.0 * PI * random(mod (uv * vec2 (textureSize(texturePosition, 0 )), float (sampleCount)));
90+
91+ for (int i = 0 ; i < sampleCount; i++ ) {
92+ // Define polar coordinates to sample on a disk around the corresponding UVs
93+ float theta = settings.samples[i].x + jitter;
94+ float r = settings.samples[i].y * maxRadius;
95+ vec2 sampleCoords = vec2 (cos (theta) * r, sin (theta) * r);
96+ // sampleCoords = ((projection * vec4(fragViewPosition + vec3(sampleCoords, 0.0), 1.0)) / depth).xy;
97+ vec2 sampleUV = (sampleCoords + 1.0 ) * 0.5 ;
98+
99+ // World radial distance computation
100+ // float sampleDepth = texture(textureDepth, sampleUV).r;
101+ // vec3 sampleViewPosition = (invProjection * (sampleDepth * vec4(sampleCoords, 0.0, 1.0))).xyz;
102+ // vec3 sampleWorldPosition = (invView * vec4(sampleViewPosition, 1.0)).xyz;
103+ vec3 sampleViewPosition = vec3 (0.0 );
104+ vec3 sampleWorldPosition = vec3 (0.0 );
105+ float radialDistance = max (distance (sampleWorldPosition, fragWorldPosition), EPS);
106+
107+ // Diffusion computation
108+ vec3 rRr = Rr(d, radialDistance); // We use r*R(r) instead of simply R(r) to integrate the disk
109+ float pr = Pr(maxRadius, r);
110+ diffusion = rRr / pr;
111+
112+ // Multiple Scattering contribution
113+ sssDiffuse += diffusion * texture(textureDiffuseLight, sampleUV).rgb;
114+ weight += diffusion;
115+
116+ // Single Scattering contribution
117+ vec3 transmittance = bsdf.scatteringDistance * exp (- attenuationCoeff * bsdf.thickness); // Translucency color (which is the scattering distance base color without scaling) * Beer-Lambert law attenuation
118+ sssDiffuse += mix (transmittance * diffusion * texture(textureDiffuseBackLight, sampleUV).rgb, vec3 (0.0 ), testScene);
119+ }
120+
121+ // Divide by sum of weights to renormalize
122+ sssDiffuse = sssDiffuse / max (weight, EPS);
123+
124+ // Blush (Hacky method)
125+ float maxCoeff = max (max (diffuse.r, diffuse.g), diffuse.b);
126+ vec3 maxChannel = step (maxCoeff, diffuse);
127+ vec3 blush = mix (maxCoeff * maxChannel * (1.0 - bsdf.thickness) * blushScale, vec3 (0.0 ), testScene);
128+
129+ return mix (diffuse, (bsdf.albedo + blush) * sssDiffuse, bsdf.mask);
130+ }
0 commit comments