mirror of
https://github.com/muskit/H3VR-TNH-Quality-of-Life-Improvements.git
synced 2026-06-02 20:24:26 -07:00
274 lines
8.6 KiB
HLSL
Vendored
274 lines
8.6 KiB
HLSL
Vendored
// Alloy Physical Shader Framework
|
|
// Copyright 2013-2017 RUST LLC.
|
|
// http://www.alloy.rustltd.com/
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
/// @file Eyeball.cginc
|
|
/// @brief Eyeball surface shader definition.
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifndef ALLOY_LEGACY_SHADERS_DEFINITION_EYEBALL_CGINC
|
|
#define ALLOY_LEGACY_SHADERS_DEFINITION_EYEBALL_CGINC
|
|
|
|
#define A_NORMAL_MAPPING_ON
|
|
#define A_VIEW_DIR_TANGENT_ON
|
|
#define A_AMBIENT_OCCLUSION_ON
|
|
#define A_SPECULAR_TINT_ON
|
|
#define A_EYE_PARALLAX_REFRACTION
|
|
#define A_DETAIL_MASK_OFF
|
|
|
|
#define A_SURFACE_CUSTOM_FIELDS \
|
|
half3 corneaNormalWorld; \
|
|
half3 irisF0; \
|
|
half scattering; \
|
|
half irisMask; \
|
|
half corneaSpecularity; \
|
|
half corneaRoughness; \
|
|
half irisSpecularOcclusion; \
|
|
half irisRoughness; \
|
|
half irisBeckmannRoughness; \
|
|
half irisNdotV;
|
|
|
|
#include "Assets/Alloy/Shaders/Framework/Lighting.cginc"
|
|
#include "Assets/Alloy/Shaders/Type/Standard.cginc"
|
|
#include "Assets/Alloy/Legacy/Shaders/Feature/EyeParallax.cginc"
|
|
|
|
/// Implements a scattering diffuse BRDF affected by roughness.
|
|
/// @param albedo Diffuse albedo LDR color.
|
|
/// @param subsurface Blend value between diffuse and scattering [0,1].
|
|
/// @param roughness Linear roughness [0,1].
|
|
/// @param LdotH Light and half-angle clamped dot product [0,1].
|
|
/// @param NdotL Normal and light clamped dot product [0,1].
|
|
/// @param NdotV Normal and view clamped dot product [0,1].
|
|
/// @return Direct diffuse BRDF.
|
|
half3 aDiffuseBssrdf(
|
|
half3 albedo,
|
|
half subsurface,
|
|
half roughness,
|
|
half LdotH,
|
|
half NdotL,
|
|
half NdotV)
|
|
{
|
|
// Impelementation of Brent Burley's diffuse scattering BRDF.
|
|
// Subject to Apache License, version 2.0
|
|
// cf https://github.com/wdas/brdf/blob/master/src/brdfs/disney.brdf
|
|
half FL = aFresnel(NdotL);
|
|
half FV = aFresnel(NdotV);
|
|
half Fss90 = LdotH * LdotH * roughness;
|
|
half Fd90 = 0.5h + (2.0h * Fss90);
|
|
half Fd = aLerpOneTo(Fd90, FL) * aLerpOneTo(Fd90, FV);
|
|
half Fss = aLerpOneTo(Fss90, FL) * aLerpOneTo(Fss90, FV);
|
|
half ss = 1.25h * (Fss * (1.0h / max(NdotL + NdotV, A_EPSILON) - 0.5h) + 0.5h);
|
|
|
|
// Pi is cancelled by implicit punctual lighting equation.
|
|
// cf http://seblagarde.wordpress.com/2012/01/08/pi-or-not-to-pi-in-game-lighting-equation/
|
|
return albedo * lerp(Fd, ss, subsurface);
|
|
}
|
|
|
|
/// A specular BRDF.
|
|
/// @param d Direct lighting data.
|
|
/// @param s Material surface data.
|
|
/// @return Direct specular BRDF.
|
|
half3 aLegacySpecularBrdf(
|
|
ADirect d,
|
|
ASurface s)
|
|
{
|
|
// Schlick's Fresnel approximation.
|
|
half3 F = lerp(s.f0, A_WHITE, aFresnel(d.LdotH));
|
|
|
|
// GGX (Trowbridge-Reitz) NDF
|
|
// cf http://graphicrants.blogspot.com/2013/08/specular-brdf-reference.html
|
|
half a2 = s.beckmannRoughness * s.beckmannRoughness;
|
|
half denom = aLerpOneTo(a2, d.NdotH * d.NdotH);
|
|
|
|
// John Hable's visibility function.
|
|
// cf http://www.filmicworlds.com/2014/04/21/optimizing-ggx-shaders-with-dotlh/
|
|
half V = lerp(a2 * 0.25h, 1.0h, d.LdotH * d.LdotH);
|
|
|
|
// Pi is cancelled by implicit punctual lighting equation.
|
|
// cf http://seblagarde.wordpress.com/2012/01/08/pi-or-not-to-pi-in-game-lighting-equation/
|
|
half DV = a2 / (4.0h * V * denom * denom);
|
|
|
|
// Cook-Torrance microfacet model.
|
|
// cf http://graphicrants.blogspot.com/2013/08/specular-brdf-reference.html
|
|
return F * (DV * s.specularOcclusion * d.specularIntensity);
|
|
}
|
|
|
|
/// Indirect specular BRDF.
|
|
/// @param s Material surface data.
|
|
/// @return Environment BRDF.
|
|
half3 aLegacyEnvironmentBrdf(
|
|
ASurface s)
|
|
{
|
|
// Brian Karis' modification of Dimitar Lazarov's Environment BRDF.
|
|
// cf https://www.unrealengine.com/blog/physically-based-shading-on-mobile
|
|
const half4 c0 = half4(-1.0h, -0.0275h, -0.572h, 0.022h);
|
|
const half4 c1 = half4(1.0h, 0.0425h, 1.04h, -0.04h);
|
|
half4 r = s.roughness * c0 + c1;
|
|
half a004 = min(r.x * r.x, exp2(-9.28h * s.NdotV)) * r.x + r.y;
|
|
half2 AB = half2(-1.04h, 1.04h) * a004 + r.zw;
|
|
return s.f0 * AB.x + AB.yyy;
|
|
}
|
|
|
|
/// Calculates standard indirect diffuse plus specular illumination.
|
|
/// @param d Indirect light description.
|
|
/// @param s Material surface data.
|
|
/// @return Indirect illumination.
|
|
half3 aLegacyStandardIndirect(
|
|
AIndirect i,
|
|
ASurface s)
|
|
{
|
|
#ifdef A_REFLECTION_PROBES_ON
|
|
half3 specular = i.specular * aLegacyEnvironmentBrdf(s);
|
|
#endif
|
|
|
|
#ifndef A_AMBIENT_OCCLUSION_ON
|
|
half3 diffuse = s.albedo * i.diffuse;
|
|
|
|
#ifndef A_REFLECTION_PROBES_ON
|
|
return diffuse;
|
|
#else
|
|
return diffuse + specular;
|
|
#endif
|
|
#else
|
|
// Yoshiharu Gotanda's fake interreflection for specular occlusion.
|
|
// Modified to better account for surface f0.
|
|
// cf http://research.tri-ace.com/Data/cedec2011_RealtimePBR_Implementation_e.pptx pg65
|
|
half3 ambient = i.diffuse * s.ambientOcclusion;
|
|
|
|
#ifndef A_REFLECTION_PROBES_ON
|
|
// Diffuse and fake interreflection only.
|
|
return ambient * (s.albedo + s.f0 * (1.0h - s.specularOcclusion));
|
|
#else
|
|
// Full equation.
|
|
return ambient * s.albedo
|
|
+ lerp(ambient * s.f0, specular, s.specularOcclusion);
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
void aPreLighting(
|
|
inout ASurface s)
|
|
{
|
|
aStandardPreLighting(s);
|
|
|
|
// Tint the iris specular to fake caustics.
|
|
// cf http://game.watch.impress.co.jp/docs/news/20121129_575412.html
|
|
|
|
// Iris & Sclera
|
|
s.irisNdotV = s.NdotV;
|
|
s.irisSpecularOcclusion = s.specularOcclusion;
|
|
s.irisF0 = s.f0;
|
|
s.irisRoughness = s.roughness;
|
|
s.irisBeckmannRoughness = s.beckmannRoughness;
|
|
|
|
// Cornea
|
|
s.roughness = lerp(s.roughness, s.corneaRoughness, s.irisMask);
|
|
s.corneaNormalWorld = normalize(lerp(s.normalWorld, s.vertexNormalWorld, s.irisMask));
|
|
s.reflectionVectorWorld = reflect(-s.viewDirWorld, s.corneaNormalWorld);
|
|
s.NdotV = aDotClamp(s.corneaNormalWorld, s.viewDirWorld);
|
|
s.FV = aFresnel(s.NdotV);
|
|
|
|
s.specularOcclusion = lerp(s.irisSpecularOcclusion, 1.0h, s.irisMask);
|
|
s.f0 = lerp(s.irisF0, aSpecularityToF0(s.corneaSpecularity), s.irisMask);
|
|
}
|
|
|
|
half3 aDirectLighting(
|
|
ADirect d,
|
|
ASurface s)
|
|
{
|
|
half3 illum = 0.0h;
|
|
|
|
// Iris & Sclera
|
|
illum = d.NdotL * (
|
|
aDiffuseBssrdf(s.albedo, s.scattering, s.irisRoughness, d.LdotH, d.NdotL, s.irisNdotV));
|
|
//+ (s.irisSpecularOcclusion * AlloyAreaLightNormalization(s.irisBeckmannRoughness, d.solidAngle)
|
|
// * aLegacySpecularBrdf(s.irisF0, s.irisBeckmannRoughness, d.LdotH, d.NdotH, d.NdotL, s.irisNdotV)));
|
|
|
|
// Cornea
|
|
d.NdotH = aDotClamp(s.corneaNormalWorld, d.halfAngleWorld);
|
|
d.NdotL = aDotClamp(s.corneaNormalWorld, d.direction);
|
|
d.specularIntensity *= s.irisMask * d.NdotL;
|
|
|
|
illum += aLegacySpecularBrdf(d, s);
|
|
return illum * d.color * d.shadow;
|
|
}
|
|
|
|
half3 aIndirectLighting(
|
|
AIndirect i,
|
|
ASurface s)
|
|
{
|
|
return aLegacyStandardIndirect(i, s);
|
|
}
|
|
|
|
/// Schlera tint color.
|
|
/// Expects a linear LDR color.
|
|
half3 _EyeScleraColor;
|
|
|
|
/// Schlera diffuse scattering amount.
|
|
/// Expects values in the range [0,1].
|
|
half _EyeScleraScattering;
|
|
|
|
/// Cornea specularity.
|
|
/// Expects values in the range [0,1].
|
|
half _EyeSpecularity;
|
|
|
|
/// Cornea roughness.
|
|
/// Expects values in the range [0,1].
|
|
half _EyeRoughness;
|
|
|
|
/// Iris tint color.
|
|
/// Expects a linear LDR color.
|
|
half3 _EyeColor;
|
|
|
|
/// Iris diffuse scattering amount.
|
|
/// Expects values in the range [0,1].
|
|
half _EyeIrisScattering;
|
|
|
|
/// Iris specular tint by base color.
|
|
/// Expects values in the range [0,1].
|
|
half _EyeSpecularTint;
|
|
|
|
void aSurfaceShader(
|
|
inout ASurface s)
|
|
{
|
|
float4 uv01 = s.uv01;
|
|
|
|
aEyeParallax(s);
|
|
aDissolve(s);
|
|
|
|
half4 base = aBase(s);
|
|
|
|
s.baseColor = base.rgb;
|
|
|
|
half4 material = aSampleMaterial(s);
|
|
|
|
s.irisMask = material.A_METALLIC_CHANNEL;
|
|
s.metallic = 0.0h;
|
|
s.ambientOcclusion = aLerpOneTo(material.A_AO_CHANNEL, _Occlusion);
|
|
s.specularity = _Specularity * material.A_SPECULARITY_CHANNEL;
|
|
s.roughness = _Roughness * material.A_ROUGHNESS_CHANNEL;
|
|
|
|
s.normalTangent = A_NT(s, aSampleBump(s));
|
|
|
|
s.baseColor *= lerp(_EyeScleraColor, _EyeColor, s.irisMask);
|
|
s.specularTint = s.irisMask * _EyeSpecularTint;
|
|
s.scattering = lerp(_EyeScleraScattering, _EyeIrisScattering, s.irisMask);
|
|
s.corneaSpecularity = _EyeSpecularity;
|
|
s.corneaRoughness = _EyeRoughness;
|
|
|
|
// Don't allow detail normals in the iris.
|
|
s.mask = 1.0h - s.irisMask;
|
|
aDetail(s);
|
|
s.mask = 1.0h;
|
|
|
|
aEmission(s);
|
|
aRim(s);
|
|
|
|
// Remove parallax so this appears on top of the cornea!
|
|
s.uv01 = uv01;
|
|
aDecal(s);
|
|
}
|
|
|
|
#endif // ALLOY_LEGACY_SHADERS_DEFINITION_EYEBALL_CGINC
|