Shader "LuckyShaders/MainGlass"
{
Properties
{
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_BumpMap ("Bump Map", 2D) = "bump" {}
_BumpIntensity ("Bump Intensity", float) = 1
_RoughnessMap ("Roughness Map", 2D) = "white" {}
_Roughness ("Roughness", Range(0,1)) = 0.5
[MaterialToggle] _RoughnessMapInverted ("Is inverted", Float) = 0
_Metallic ("Metallic", Range(0,1)) = 0.0
_SpecularMap ("Specular Map", 2D) = "white" {}
_SpecularIntensity ("Specular Intensity", float) = 1
_DispMap ("Displacement Map", 2D) = "gray" {}
_DispIntensity ("Displacement", float) = 0
_Tesselation ("Tesselation", Range(1,32)) = 4
_WetMap ("Wetness Map", 2D) = "gray" {}
_Wetness ("Wetness", Range(0,1)) = 0
_WaterColor ("Water Color", Color) = (0.87, 0.92, 1, 0.15)
_AOMap ("AO Map", 2D) = "white" {}
_IOR ("Index of Refraction", float) = 1
}
SubShader
{
Tags { "RenderType"="Transparent" "Queue"="Transparent" }
LOD 200
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
// Physically based Standard lighting model, and enable shadows on all light types
//#pragma surface surf Standard fullforwardshadows
#pragma surface surf Burley addshadow fullforwardshadows vertex:disp tessellate:tessFixed
#pragma target 4.6
struct appdata {
float4 vertex : POSITION;
float4 tangent : TANGENT;
float3 normal : NORMAL;
float2 texcoord : TEXCOORD0;
//These are needed for lightmaps and GI
float2 texcoord1 : TEXCOORD1;
float2 texcoord2 : TEXCOORD2;
};
//Define certain default variables like PI
static const float PI = 3.14159265;
static const float INV_PI = 0.3183098865475127719056765682209; //TODO: see if reducing accuraccy leads to better performance without negative results
//Custom lighting model
struct SurfaceOutputBurley {
fixed3 Albedo;
fixed3 Normal;
fixed3 Emission;
fixed Metallic;
fixed Roughness;
half Specular;
fixed Alpha;
fixed Height;
fixed IOR;
};
float pow5 (float x) {
float x2 = x * x;
return x2 * x2 * x;
}
float D_GGX (float linearRoughness, float NoH) {
//Walter et al. 2007, "Microfacet Models for Refraction through Rough Surfaces"
float oneMinusNoHSquared = 1.0 - NoH * NoH;
float a = NoH * linearRoughness;
float k = linearRoughness / (oneMinusNoHSquared + a * a);
return k * k * INV_PI; //d
}
float V_SmithGGXCorrelated (float linearRoughness, float NoV, float NoL) {
//Heitz 2014, "Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs"
float a2 = linearRoughness * linearRoughness;
float GGXV = NoL * sqrt((NoV - a2 * NoV) * NoV + a2);
float GGXL = NoV * sqrt((NoL - a2 * NoL) * NoL + a2);
return 0.5 / (GGXV + GGXL);
}
float3 F_Schlick (float3 f0, float VoH) {
//Schlick 1994, "An Inexpensive BRDF Model for Physically-Based Rendering"
return f0 + (float3(1.0,1.0,1.0) - f0) * pow5(1.0 - VoH);
}
float F_Schlick (float f0, float f90, float VoH) {
return f0 + (f90 - f0) * pow5(1.0 - VoH);
}
float Fd_Burley (float linearRoughness, float NoV, float NoL, float LoH) {
//Burley 2012, "Physically-Based Shading at Disney"
float f90 = 0.5 + 2.0 * linearRoughness * LoH * LoH;
float lightScatter = F_Schlick(1.0, f90, NoL);
float viewScatter = F_Schlick(1.0, f90, NoV);
return lightScatter * viewScatter * INV_PI;
}
//In original code Fd_Lambert was defined as 1.0 / PI, but we can just replace this with using INV_PI
float3 Irradiance_SphericalHarmonics (float3 n) {
//Irradiance from "Ditch River" IBL (http://www.hdrlabs.com/sibl/archive.html)
return max(
float3( 0.754554516862612, 0.748542953903366, 0.790921515418539)
+ float3(-0.083856548007422, 0.092533500963210, 0.322764661032516) * (n.y)
+ float3( 0.308152705331738, 0.366796330467391, 0.466698181299906) * (n.z)
+ float3(-0.188884931542396, -0.277402551592231, -0.377844212327557) * (n.x)
, float3(0.0, 0.0, 0.0)
);
}
float2 PrefilteredDFG_Karis (float roughness, float NoV) {
//Karis 2014, "Physically Based Material on Mobile"
const float4 c0 = float4(-1.0, -0.0275, -0.572, 0.022);
const float4 c1 = float4( 1.0, 0.0425, 1.040, -0.040);
float4 r = roughness * c0 + c1;
float a004 = min(r.x * r.x, exp2(-9.28 * NoV)) * r.x + r.y;
return float2(-1.04, 1.04) * a004 + r.zw;
}
//inline fixed4 LightingBurleyLight (SurfaceOutputBurley s, half3 viewDir, half attenuation, UnityLight light, UnityIndirect indirect)
//inline fixed4 LightingBurleyLight (SurfaceOutputBurley s, half3 viewDir, half attenuation, half3 lightDir, fixed4 ref)
inline fixed4 LightingBurleyLight (SurfaceOutputBurley s, half3 viewDir, half attenuation, half3 lightDir, fixed4 ref, UnityIndirect indirect)
{
//Variables from original code:
//vec3 pos (position)
//vec3 n (normal)
//vec3 rd (view direction)
//vec3 l (incoming light direction)
//vec3 lp (light position)
//float range (light range)
//vec3 baseColor (surface color)
//float roughness (self-explanatory)
//float metallic (self-explanatory)
//Seeing as unity handles a lot of light calculations itself, all I need to do is use these :D
float3 v = normalize(-viewDir);
float3 h = normalize(v + lightDir);
float3 r = normalize(reflect(viewDir, s.Normal));
float NoV = abs(dot(s.Normal, v)) + 1e-5;
float NoL = saturate(dot(s.Normal, lightDir));
float NoH = saturate(dot(s.Normal, h));
float LoH = saturate(dot(lightDir, h));
//Upon further inspection, it appears unity already multiplies light color with intensity.
//EDIT: I have worked through a bunch of fucking issues, like not being able to access attenuation when using _GI functions and shit like that
//so now with attenuation, we actually need these variables again to get more accurate colors.
float intensity = 2.0; //Original code specified 2.0
float indirectIntensity = 0.64; //Original code specified 0.64
//Because of what I said in the previous comment, we don't actually need to do this hacky math for point lights that I used to do in GLSL lol
float linearRoughness = s.Roughness * s.Roughness;
float3 diffuseColor = (1.0 - s.Metallic) * s.Albedo + ref.rgb * s.Metallic * linearRoughness;
float3 f0 = 0.04 * (1.0 - s.Metallic) + s.Albedo * s.Metallic;
//Original code specified attenuation here, meaning the intensity of the shadow.
//No need though, because Unity already multiplies light color by intensity beforehand.
//Pretty nice, but I still think Unity sucks because it limits you so much.
//Custom Deferred lighting models are basically not doable, because fuck you that's why lol.
//Anyway
float fLinearRoughness = (0.5 + s.Roughness*0.5) * (0.5 + s.Roughness*0.5);
//Specular BRDF
float D = D_GGX(linearRoughness, NoH);
float V = V_SmithGGXCorrelated(linearRoughness, NoV, NoL);
float3 F = F_Schlick(f0, LoH);
float3 Fr = (D * V) * F; //for real dude :p
//Diffuse BRDF
float3 Fd = diffuseColor * Fd_Burley(linearRoughness, NoV, NoL, LoH);
float3 color = Fd + Fr;
color *= (intensity * attenuation * NoL);
float3 ibl; //This was defined beforehand because of the code below.
//TODO: Fix this fucking mess
#ifdef UNITY_LIGHT_FUNCTION_APPLY_INDIRECT
float3 indirectDiffuse = Irradiance_SphericalHarmonics(s.Normal) * INV_PI; //Normally it uses Fd_Lambert() here, but we replaced that with INV_PI
float3 indirectSpecular = indirect.diffuse; //Original code actually gets this value from a raycast, because it is taken from a sphere tracer :D
//Indirect contribution
float2 dfg = PrefilteredDFG_Karis(s.Roughness, NoV);
float3 specularColor = f0 * dfg.x + dfg.y;
ibl = diffuseColor * indirect.diffuse + indirect.specular * specularColor * intensity * attenuation * (float3(0.7, 0.9, 1.0) + viewDir.y * 0.8) * 6.0 * s.Specular;
#endif
#ifndef UNITY_LIGHT_FUNCTION_APPLY_INDIRECT
float2 dfg = PrefilteredDFG_Karis(s.Roughness, NoV);
float3 specularColor = f0 * dfg.x + dfg.y;
ibl = diffuseColor + specularColor * intensity * attenuation * (float3(0.7, 0.9, 1.0) + viewDir.y * 0.8) * 6.0 * s.Specular;
#endif
//float2 dfg = PrefilteredDFG_Karis(s.Roughness, NoV);
//float3 specularColor = f0 * dfg.x + dfg.y;
//ibl = diffuseColor + specularColor * intensity * attenuation * (float3(0.7, 0.9, 1.0) + viewDir.y * 0.8) * 6.0 * s.Specular;
return float4(color * ibl * (_LightColor0.rgb * intensity), 1.0);
}
inline fixed4 LightingBurleyReflect (SurfaceOutputBurley s, half3 lightDir, half3 viewDir, half atten)
{
float4 hdrReflection = 1.0;
float3 reflectedDir = reflect(viewDir, s.Normal);
float4 reflection = UNITY_SAMPLE_TEXCUBE(unity_SpecCube0, reflectedDir);
hdrReflection.rgb = DecodeHDR(reflection, unity_SpecCube0_HDR);
hdrReflection.a = 1.0;
float4 c;
c.rgb = hdrReflection;
return c;
}
inline fixed4 LightingBurley (SurfaceOutputBurley s, half3 lightDir, half3 viewDir, half atten, UnityIndirect indirect)
{
fixed4 ref = LightingBurleyReflect (s, lightDir, viewDir, atten);
fixed4 c = LightingBurleyLight (s, viewDir, atten, lightDir, ref, indirect);
float3 refractedDir = refract(viewDir, s.Normal, 1.0 / s.IOR);
float4 refraction = UNITY_SAMPLE_TEXCUBE(unity_SpecCube0, refractedDir);
c.rgb = c.rgb * s.Alpha + (1.0 - s.Alpha) * refraction.rgb;
c.a = s.Alpha;
return c;
}
sampler2D _MainTex;
sampler2D _RoughnessMap;
sampler2D _SpecularMap;
sampler2D _BumpMap;
sampler2D _DispMap;
sampler2D _WetMap;
sampler2D _AOMap;
struct Input
{
float2 uv_MainTex;
};
fixed _Roughness;
fixed _RoughnessMapInverted;
fixed _Metallic;
fixed _SpecularIntensity;
fixed _BumpIntensity;
fixed _DispIntensity;
fixed _Tesselation;
fixed _Wetness;
fixed _IOR;
fixed4 _WaterColor;
fixed4 _Color;
// Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
// See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
// #pragma instancing_options assumeuniformscaling
UNITY_INSTANCING_BUFFER_START(Props)
// put more per-instance properties here
UNITY_INSTANCING_BUFFER_END(Props)
float4 tessFixed()
{
return _Tesselation;
}
void disp (inout appdata v)
{
float d = tex2Dlod(_DispMap, float4(v.texcoord.xy, 0,0)).r * _DispIntensity;
v.vertex.xyz += v.normal * d;
}
void surf (Input IN, inout SurfaceOutputBurley o)
{
fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color.a;
c.rgb *= tex2D (_AOMap, IN.uv_MainTex).r;
fixed4 w = tex2D (_WetMap, IN.uv_MainTex);
fixed3 ww = w.r * _WaterColor * _Wetness;
o.Albedo = (1.0 - _Wetness * w.r) * c.rgb + (ww * c.rgb * w.a);
//o.Albedo = float3(_Color.a, _Color.a, _Color.a);
o.Metallic = _Metallic;
fixed roughness = _Roughness;
if (_RoughnessMapInverted > 0) {
roughness *= (1.0 - tex2D (_RoughnessMap, IN.uv_MainTex).r);
} else {
roughness *= tex2D (_RoughnessMap, IN.uv_MainTex).r;
}
o.Roughness = (1.0 - _Wetness * w.r) * roughness + _Wetness * w.r;
o.Specular = (1.0 - _Wetness * w.r) * (tex2D (_SpecularMap, IN.uv_MainTex) * _SpecularIntensity) + _Wetness * w.r;
o.Normal = (1.0 - _Wetness * w.r) * (UnpackNormal(tex2D (_BumpMap, IN.uv_MainTex) * _BumpIntensity)) + _Wetness * w.r * float3(1.0, 1.0, 1.0);
o.IOR = _IOR;
o.Alpha = _Color.a;
}
ENDCG
}
//FallBack "Diffuse"
}