summaryrefslogtreecommitdiff
path: root/VRCSDK3Avatars/Assets/Resources/RalivDynamicPenetrationSystem/Plugins/Xiexes-Unity-Shaders-development/Main/CGIncludes/XSLightingFunctions.cginc
blob: f28f6f2995b104e24995436b26d5a61979749e53 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
//Helper Functions for Reflections
float pow5(float a)
{
    return a * a * a * a * a;
}

float3 F_Schlick(float u, float3 f0)
{
    return f0 + (1.0 - f0) * pow(1.0 - u, 5.0);
}

float3 F_FresnelLerp (float3 F0, float3 F90, float cosA)
{
    float t = pow5(1 - cosA);   // ala Schlick interpoliation
    return lerp (F0, F90, t);
}

float D_GGX(float NoH, float roughness)
{
    float a2 = roughness * roughness;
    float f = (NoH * a2 - NoH) * NoH + 1.0;
    return a2 / (UNITY_PI * f * f);
}

float D_GGX_Anisotropic(float NoH, const float3 h, const float3 t, const float3 b, float at, float ab)
{
    float ToH = dot(t, h);
    float BoH = dot(b, h);
    float a2 = at * ab;
    float3 v = float3(ab * ToH, at * BoH, a2 * NoH);
    float v2 = dot(v, v);
    float w2 = a2 / v2;
    return a2 * w2 * w2 * (1.0 / UNITY_PI);
}

float V_SmithGGXCorrelated(float NoV, float NoL, float a)
{
    float a2 = a * a;
    float GGXL = NoV * sqrt((-NoL * a2 + NoL) * NoL + a2);
    float GGXV = NoL * sqrt((-NoV * a2 + NoV) * NoV + a2);
    return 0.5 / (GGXV + GGXL);
}

half3 calcReflView(half3 viewDir, half3 normal)
{
    return reflect(-viewDir, normal);
}

half3 calcReflLight(half3 lightDir, half3 normal)
{
    return reflect(lightDir, normal);
}
//

//Returns the average direction of all lights and writes to a struct contraining individual directions
float3 getVertexLightsDir(inout VertexLightInformation vLights, float3 worldPos, float4 vertexLightAtten)
{
    float3 dir = float3(0,0,0);
    float3 toLightX = float3(unity_4LightPosX0.x, unity_4LightPosY0.x, unity_4LightPosZ0.x);
    float3 toLightY = float3(unity_4LightPosX0.y, unity_4LightPosY0.y, unity_4LightPosZ0.y);
    float3 toLightZ = float3(unity_4LightPosX0.z, unity_4LightPosY0.z, unity_4LightPosZ0.z);
    float3 toLightW = float3(unity_4LightPosX0.w, unity_4LightPosY0.w, unity_4LightPosZ0.w);

    float3 dirX = toLightX - worldPos;
    float3 dirY = toLightY - worldPos;
    float3 dirZ = toLightZ - worldPos;
    float3 dirW = toLightW - worldPos;

    dirX *= length(toLightX) * vertexLightAtten.x;
    dirY *= length(toLightY) * vertexLightAtten.y;
    dirZ *= length(toLightZ) * vertexLightAtten.z;
    dirW *= length(toLightW) * vertexLightAtten.w;

    vLights.Direction[0] = dirX;
    vLights.Direction[1] = dirY;
    vLights.Direction[2] = dirZ;
    vLights.Direction[3] = dirW;

    dir = (dirX + dirY + dirZ + dirW) / 4;
    return dir;
}

// Get the most intense light Dir from probes OR from a light source. Method developed by Xiexe / Merlin
half3 calcLightDir(XSLighting i)
{
    half3 lightDir = UnityWorldSpaceLightDir(i.worldPos);
    half3 probeLightDir = unity_SHAr.xyz + unity_SHAg.xyz + unity_SHAb.xyz;
    lightDir = (lightDir + probeLightDir); //Make light dir the average of the probe direction and the light source direction.
    #if !defined(POINT) && !defined(SPOT)// if the average length of the light probes is null, and we don't have a directional light in the scene, fall back to our fallback lightDir
        if(length(unity_SHAr.xyz*unity_SHAr.w + unity_SHAg.xyz*unity_SHAg.w + unity_SHAb.xyz*unity_SHAb.w) == 0 && length(lightDir) < 0.1)
        {
            lightDir = half4(1, 1, 1, 0);
        }
    #endif
    return normalize(lightDir);
}

void calcLightCol(bool lightEnv, inout half3 indirectDiffuse, inout half4 lightColor)
{
    //If we're in an environment with a realtime light, then we should use the light color, and indirect color raw.
    //...
    if(lightEnv)
    {
        lightColor = _LightColor0;
        indirectDiffuse = indirectDiffuse;
    }
    else
    {
        lightColor = indirectDiffuse.xyzz * 0.6;    // ...Otherwise
        indirectDiffuse = indirectDiffuse * 0.4;    // Keep overall light to 100% - these should never go over 100%
                                                    // ex. If we have indirect 100% as the light color and Indirect 50% as the indirect color,
                                                    // we end up with 150% of the light from the scene.
    }
}

float3 get4VertexLightsColFalloff(inout VertexLightInformation vLight, float3 worldPos, float3 normal, inout float4 vertexLightAtten)
{
    float3 lightColor = 0;
    #if defined(VERTEXLIGHT_ON)
    float4 toLightX = unity_4LightPosX0 - worldPos.x;
    float4 toLightY = unity_4LightPosY0 - worldPos.y;
    float4 toLightZ = unity_4LightPosZ0 - worldPos.z;

    float4 lengthSq = 0;
    lengthSq += toLightX * toLightX;
    lengthSq += toLightY * toLightY;
    lengthSq += toLightZ * toLightZ;

    float4 atten = 1.0 / (1.0 + lengthSq * unity_4LightAtten0);
    float4 atten2 = saturate(1 - (lengthSq * unity_4LightAtten0 / 25));
    atten = min(atten, atten2 * atten2);
    // Cleaner, nicer looking falloff. Also prevents the "Snapping in" effect that Unity's normal integration of vertex lights has.
    vertexLightAtten = atten;

    lightColor.rgb += unity_LightColor[0] * atten.x;
    lightColor.rgb += unity_LightColor[1] * atten.y;
    lightColor.rgb += unity_LightColor[2] * atten.z;
    lightColor.rgb += unity_LightColor[3] * atten.w;

    vLight.ColorFalloff[0] = unity_LightColor[0] * atten.x;
    vLight.ColorFalloff[1] = unity_LightColor[1] * atten.y;
    vLight.ColorFalloff[2] = unity_LightColor[2] * atten.z;
    vLight.ColorFalloff[3] = unity_LightColor[3] * atten.w;

    vLight.Attenuation[0] = atten.x;
    vLight.Attenuation[1] = atten.y;
    vLight.Attenuation[2] = atten.z;
    vLight.Attenuation[3] = atten.w;
    #endif
    return lightColor;
}

half4 calcRamp(XSLighting i, DotProducts d)
{
    half remapRamp;
    remapRamp = (d.ndl * 0.5 + 0.5) * lerp(1, i.occlusion.r, _OcclusionMode) ;
    #if defined(UNITY_PASS_FORWARDBASE)
    remapRamp *= i.attenuation;
    #endif
    half4 ramp = tex2D(_Ramp, half2(remapRamp, i.rampMask.r));
    return ramp;
}

half4 calcRampShadowOverride(XSLighting i, float ndl)
{
    half remapRamp;
    remapRamp = (ndl * 0.5 + 0.5) * lerp(1, i.occlusion.r, _OcclusionMode);
    half4 ramp = tex2D(_Ramp, half2(remapRamp, i.rampMask.r));
    return ramp;
}

float3 getVertexLightsDiffuse(XSLighting i, VertexLightInformation vLight)
{
    float3 vertexLightsDiffuse = 0;
    #if defined(VERTEXLIGHT_ON)
        for(int light = 0; light < 4; light++) // I know, I know, not using i. Blame my structs.
        {
            float vLightNdl = dot(vLight.Direction[light], i.normal);
            vertexLightsDiffuse += calcRampShadowOverride(i, vLightNdl) * vLight.ColorFalloff[light];
        }
    #endif
    return vertexLightsDiffuse;
}

half4 calcMetallicSmoothness(XSLighting i)
{
    half roughness = 1-(_Glossiness * i.metallicGlossMap.a);
    roughness *= 1.7 - 0.7 * roughness;
    half metallic = lerp(0, i.metallicGlossMap.r * _Metallic, i.reflectivityMask.r);
    return half4(metallic, 0, 0, roughness);
}

half4 calcRimLight(XSLighting i, DotProducts d, half4 lightCol, half3 indirectDiffuse, half3 envMap)
{
    half rimIntensity = saturate((1-d.svdn)) * pow(d.ndl, _RimThreshold);
    rimIntensity = smoothstep(_RimRange - _RimSharpness, _RimRange + _RimSharpness, rimIntensity);
    half4 rim = rimIntensity * _RimIntensity * (lightCol + indirectDiffuse.xyzz);
    rim *= lerp(1, i.attenuation + indirectDiffuse.xyzz, _RimAttenEffect);
    return rim * _RimColor * lerp(1, i.diffuseColor.rgbb, _RimAlbedoTint) * lerp(1, envMap.rgbb, _RimCubemapTint);
}

half4 calcShadowRim(XSLighting i, DotProducts d, half3 indirectDiffuse)
{
    half rimIntensity = saturate((1-d.svdn)) * pow(1-d.ndl, _ShadowRimThreshold * 2);
    rimIntensity = smoothstep(_ShadowRimRange - _ShadowRimSharpness, _ShadowRimRange + _ShadowRimSharpness, rimIntensity);
    half4 shadowRim = lerp(1, (_ShadowRim * lerp(1, i.diffuseColor.rgbb, _ShadowRimAlbedoTint)) + (indirectDiffuse.xyzz * 0.1), rimIntensity);

    return shadowRim ;
}

float3 getAnisotropicReflectionVector(float3 viewDir, float3 bitangent, float3 tangent, float3 normal, float roughness, float anisotropy)
{
    //_Anisotropy = lerp(-0.2, 0.2, sin(_Time.y / 20)); //This is pretty fun
    float3 anisotropicDirection = anisotropy >= 0.0 ? bitangent : tangent;
    float3 anisotropicTangent = cross(anisotropicDirection, viewDir);
    float3 anisotropicNormal = cross(anisotropicTangent, anisotropicDirection);
    float bendFactor = abs(anisotropy) * saturate(5.0 * roughness);
    float3 bentNormal = normalize(lerp(normal, anisotropicNormal, bendFactor));
    return reflect(-viewDir, bentNormal);
}

half3 calcDirectSpecular(XSLighting i, float ndl, float ndh, float vdn, float ldh, half4 lightCol, half3 halfVector, half anisotropy)
{
    half specularIntensity = _SpecularIntensity * i.specularMap.r;
    half3 specular = half3(0,0,0);
    half smoothness = max(0.01, (_SpecularArea * i.specularMap.b));
    smoothness *= 1.7 - 0.7 * smoothness;

    float rough = max(smoothness * smoothness, 0.0045);
    float Dn = D_GGX(ndh, rough);
    float3 F = 1-F_Schlick(ldh, 0);
    float V = V_SmithGGXCorrelated(vdn, ndl, rough);
    float3 directSpecularNonAniso = max(0, (Dn * V) * F);

    anisotropy *= saturate(5.0 * smoothness);
    float at = max(rough * (1.0 + anisotropy), 0.001);
    float ab = max(rough * (1.0 - anisotropy), 0.001);
    float D = D_GGX_Anisotropic(ndh, halfVector, i.tangent, i.bitangent, at, ab);
    float3 directSpecularAniso = max(0, (D * V) * F);

    specular = lerp(directSpecularNonAniso, directSpecularAniso, saturate(abs(anisotropy * 100)));
    specular = lerp(specular, smoothstep(0.5, 0.51, specular), _SpecularSharpness) * 3 * lightCol * specularIntensity; // Multiply by 3 to bring up to brightness of standard
    specular *= lerp(1, i.diffuseColor, _SpecularAlbedoTint * i.specularMap.g);
    return specular;
}

float3 getVertexLightSpecular(XSLighting i, DotProducts d, VertexLightInformation vLight, float3 normal, float3 viewDir, float anisotropy)
{
    float3 vertexLightSpec = 0;
    #if defined(VERTEXLIGHT_ON)
        for(int light = 0; light < 4; light++)
        {
            // All of these need to be recalculated for each individual light to treat them how we want to treat them.
            float3 vHalfVector = normalize(vLight.Direction[light] + viewDir);
            float vNDL = saturate(dot(vLight.Direction[light], normal));
            float vLDH = saturate(dot(vLight.Direction[light], vHalfVector));
            float vNDH = saturate(dot(normal, vHalfVector));
            vertexLightSpec += calcDirectSpecular(i, vNDL, vNDH, d.vdn, vLDH, vLight.ColorFalloff[light].rgbb, vHalfVector, anisotropy) * vNDL;
        }
    #endif
    return vertexLightSpec;
}

half3 calcIndirectSpecular(XSLighting i, DotProducts d, half4 metallicSmoothness, half3 reflDir, half3 indirectLight, half3 viewDir, float3 fresnel, half4 ramp)
{//This function handls Unity style reflections, Matcaps, and a baked in fallback cubemap.
    half3 spec = half3(0,0,0);

    UNITY_BRANCH
    if(_ReflectionMode == 0) // PBR
    {
        #if defined(UNITY_PASS_FORWARDBASE) //Indirect PBR specular should only happen in the forward base pass. Otherwise each extra light adds another indirect sample, which could mean you're getting too much light.
            half3 reflectionUV1 = getReflectionUV(reflDir, i.worldPos, unity_SpecCube0_ProbePosition, unity_SpecCube0_BoxMin, unity_SpecCube0_BoxMax);
            half4 probe0 = UNITY_SAMPLE_TEXCUBE_LOD(unity_SpecCube0, reflectionUV1, metallicSmoothness.w * UNITY_SPECCUBE_LOD_STEPS);
            half3 probe0sample = DecodeHDR(probe0, unity_SpecCube0_HDR);

            half3 indirectSpecular;
            half interpolator = unity_SpecCube0_BoxMin.w;

            UNITY_BRANCH
            if (interpolator < 0.99999)
            {
                half3 reflectionUV2 = getReflectionUV(reflDir, i.worldPos, unity_SpecCube1_ProbePosition, unity_SpecCube1_BoxMin, unity_SpecCube1_BoxMax);
                half4 probe1 = UNITY_SAMPLE_TEXCUBE_SAMPLER_LOD(unity_SpecCube1, unity_SpecCube0, reflectionUV2, metallicSmoothness.w * UNITY_SPECCUBE_LOD_STEPS);
                half3 probe1sample = DecodeHDR(probe1, unity_SpecCube1_HDR);
                indirectSpecular = lerp(probe1sample, probe0sample, interpolator);
            }
            else
            {
                indirectSpecular = probe0sample;
            }

            if (!any(indirectSpecular))
            {
                indirectSpecular = texCUBElod(_BakedCubemap, half4(reflDir, metallicSmoothness.w * UNITY_SPECCUBE_LOD_STEPS));
                indirectSpecular *= indirectLight;
            }
            spec = indirectSpecular * fresnel;
        #endif
    }
    else if(_ReflectionMode == 1) //Baked Cubemap
    {
        half3 indirectSpecular = texCUBElod(_BakedCubemap, half4(reflDir, metallicSmoothness.w * UNITY_SPECCUBE_LOD_STEPS));;
        spec = indirectSpecular * fresnel;

        if(_ReflectionBlendMode != 1)
        {
            spec *= (indirectLight + (_LightColor0 * i.attenuation) * 0.5);
        }
    }
    else if (_ReflectionMode == 2) //Matcap
    {
        half3 upVector = half3(0,1,0);
        half2 remapUV = matcapSample(upVector, viewDir, i.normal);
        spec = tex2Dlod(_Matcap, half4(remapUV, 0, ((1-metallicSmoothness.w) * UNITY_SPECCUBE_LOD_STEPS))) * _MatcapTint;

        if(_ReflectionBlendMode != 1)
        {
            spec *= (indirectLight + (_LightColor0 * i.attenuation) * 0.5);
        }

        spec *= lerp(1, i.diffuseColor, _MatcapTintToDiffuse);
    }
    return spec;
}

half4 calcOutlineColor(XSLighting i, DotProducts d, half3 indirectDiffuse, half4 lightCol)
{
    half3 outlineColor = half3(0,0,0);
    #if defined(Geometry)
        half3 ol = lerp(_OutlineColor, _OutlineColor * i.diffuseColor, _OutlineAlbedoTint);
        outlineColor = ol * saturate(i.attenuation * d.ndl) * lightCol.rgb;
        outlineColor += indirectDiffuse * ol;
        outlineColor = lerp(outlineColor, ol, _OutlineLighting);
    #endif
    return half4(outlineColor,1);
}

half3 calcIndirectDiffuse(XSLighting i)
{// We don't care about anything other than the color from probes for toon lighting.
    half3 indirectDiffuse = ShadeSH9(float4(0,0.5,0,1));//half3(unity_SHAr.w, unity_SHAg.w, unity_SHAb.w);
    return indirectDiffuse;
}

half4 calcDiffuse(XSLighting i, DotProducts d, half3 indirectDiffuse, half4 lightCol, half4 ramp)
{
    half4 diffuse;
    half4 indirect = indirectDiffuse.xyzz;

    half grayIndirect = dot(indirectDiffuse, float3(1,1,1));
    half attenFactor = lerp(i.attenuation, 1, smoothstep(0, 0.2, grayIndirect));

    diffuse = ramp * attenFactor * lightCol + indirect;
    diffuse = i.albedo * diffuse;
    return diffuse;
}

//Subsurface Scattering - Based on a 2011 GDC Conference from by Colin Barre-Bresebois & Marc Bouchard
//Modified by Xiexe
half4 calcSubsurfaceScattering(XSLighting i, DotProducts d, half3 lightDir, half3 viewDir, half3 normal, half4 lightCol, half3 indirectDiffuse)
{
    UNITY_BRANCH
    if(any(_SSColor.rgb)) // Skip all the SSS stuff if the color is 0.
    {
        //d.ndl = smoothstep(_SSSRange - _SSSSharpness, _SSSRange + _SSSSharpness, d.ndl);
        half attenuation = saturate(i.attenuation * (d.ndl * 0.5 + 0.5));
        half3 H = normalize(lightDir + normal * _SSDistortion);
        half VdotH = pow(saturate(dot(viewDir, -H)), _SSPower);
        half3 I = _SSColor * (VdotH + indirectDiffuse) * attenuation * i.thickness * _SSScale;
        half4 SSS = half4(lightCol.rgb * I * i.albedo.rgb, 1);
        SSS = max(0, SSS); // Make sure it doesn't go NaN

        return SSS;
    }
    else
    {
        return 0;
    }
}

half4 calcEmission(XSLighting i, half lightAvg)
{
    #if defined(UNITY_PASS_FORWARDBASE) // Emission only in Base Pass, and vertex lights
        float4 emission = lerp(i.emissionMap, i.emissionMap * i.diffuseColor.xyzz, _EmissionToDiffuse);
        float4 scaledEmission = emission * saturate(smoothstep(1-_ScaleWithLightSensitivity, 1+_ScaleWithLightSensitivity, 1-lightAvg));
        float4 em = lerp(scaledEmission, emission, _ScaleWithLight);

        em.rgb = rgb2hsv(em.rgb);
        em.x += fmod(_Hue, 360);
        em.y = saturate(em.y * _Saturation);
        em.z *= _Value;
        em.rgb = hsv2rgb(em.rgb);

        return em;
    #else
        return 0;
    #endif
}

void calcReflectionBlending(XSLighting i, inout half4 col, half3 indirectSpecular)
{
    if(_ReflectionBlendMode == 0) // Additive
        col += indirectSpecular.xyzz * i.reflectivityMask.r;
    else if(_ReflectionBlendMode == 1) //Multiplicitive
        col = lerp(col, col * indirectSpecular.xyzz, i.reflectivityMask.r);
    else if(_ReflectionBlendMode == 2) //Subtractive
        col -= indirectSpecular.xyzz * i.reflectivityMask.r;
}

void calcClearcoat(inout half4 col, XSLighting i, DotProducts d, half3 untouchedNormal, half3 indirectDiffuse, half3 lightCol, half3 viewDir, half3 lightDir, half4 ramp)
{
    UNITY_BRANCH
    if(_ClearCoat != 0)
    {
        untouchedNormal = normalize(untouchedNormal);
        half clearcoatSmoothness = _ClearcoatSmoothness * i.metallicGlossMap.g;
        half clearcoatStrength = _ClearcoatStrength * i.metallicGlossMap.b;

        half3 reflView = calcReflView(viewDir, untouchedNormal);
        half3 reflLight = calcReflLight(lightDir, untouchedNormal);
        half rdv = saturate( dot( reflLight, half4(-viewDir, 0) ));
        half3 clearcoatIndirect = calcIndirectSpecular(i, d, half4(0, 0, 0, 1-clearcoatSmoothness), reflView, indirectDiffuse, viewDir, 1, ramp);
        half3 clearcoatDirect = saturate(pow(rdv, clearcoatSmoothness * 256)) * i.attenuation * lightCol;

        half3 clearcoat = (clearcoatIndirect + clearcoatDirect) * clearcoatStrength;
        clearcoat = lerp(clearcoat * 0.5, clearcoat, saturate(pow(1-dot(viewDir, untouchedNormal), 0.8)) );
        col += clearcoat.xyzz;
    }
}