ToriaAssets/Sources/Shaders/SFB_Fur.shader
2026-05-19 15:33:18 +02:00

374 lines
12 KiB
GLSL

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'
Shader "SFBayStudios/Fur" {
Properties {
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
[HideInInspector]_Glossiness ("Smoothness", Range(0,1)) = 0.5
[HideInInspector]_Metallic ("Metallic", Range(0,1)) = 0.0
_Density ("Fur Density", Range(0,12)) = 1
_Volume ("Fur Volume", Range(-10,10)) = 0.0
_Fuziness ("Fur Fuziness", Range(0,1)) = 0.5
_FurDepth("Fur Base", Range(0,1)) = 0.5
_FurLight("Fur Light", Range(0,1)) = 0.5
[HideInInspector]_Threshold("Threshold", Range(0,1)) = 0.25
_Cutoff ("Shadow", Range(0,1)) = 0.5
}
SubShader{
Tags {
"Queue"="Transparent"
"RenderType"="Transparent"
}
Pass {
Name "FORWARD"
Tags {
"LightMode"="ForwardBase"
}
Blend SrcAlpha OneMinusSrcAlpha
ZWrite OFF
Cull OFF
CGPROGRAM
#pragma vertex vert
#pragma geometry geom
#pragma fragment frag
#include "UnityCG.cginc"
uniform sampler2D _MainTex;
uniform sampler2D _Normal;
uniform sampler2D _CameraDepthTexture; //Depth Texture
uniform float _Metallic;
//HAIR
uniform int _Density;
uniform float _Volume;
uniform float _Fuziness;
uniform float _FurLight;
uniform float _Threshold;
uniform float _FurDepth;
uniform float4 _LightColor0;
#define TAM 36
struct VertexInput
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float3 normal: NORMAL;
float4 tangent: TANGENT;
};
struct v2g
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float3 normal: NORMAL;
float4 tangent: TANGENT;
float4 projPos : TEXCOORD1;
float4 worldPos : TEXCOORD2;
};
struct g2f
{
float4 pos : POSITION;
float2 uv : TEXCOORD0;
float3 normal: NORMAL;
float4 tangent: TANGENT;
float4 projPos : TEXCOORD1;
float4 worldPos : TEXCOORD2;
};
v2g vert(VertexInput v) {
v2g o;
o.vertex = v.vertex;
o.uv = v.uv;
o.normal = v.normal;
o.tangent = v.tangent;
o.worldPos = mul(unity_ObjectToWorld, v.vertex);
float4 pos = UnityObjectToClipPos(v.vertex);
o.projPos = ComputeScreenPos(pos);
return o;
}
[maxvertexcount(TAM)] //point || triangle
void geom(triangle v2g p[3], inout TriangleStream<g2f> triStream){
g2f tri;
for (int j = 0; j < _Density; j++){
for (int k = 0; k < 3; k++){
float4 adjust = float4( p[k].vertex.xyz + p[k].normal * _Volume * j, p[k].vertex.w);
tri.pos = UnityObjectToClipPos(adjust);
tri.uv = p[k].uv;
tri.normal = p[k].normal;
tri.tangent = p[k].tangent;
tri.worldPos = p[k].worldPos;
tri.projPos = p[k].projPos;
triStream.Append(tri);
}
triStream.RestartStrip();
}
}
//REFLECTION
float3 R(float3 L, float3 N){
return L - 2.0 * dot(N, L) * N;
}
float3 unpack(float4 input){
#if defined(SHADER_API_GLES) && defined(SHADER_API_MOBILE)
return input.xyz * 2 - 1;
#else
float3 normal;
normal.xy = input.wy * 2 - 1;
normal.z = sqrt(1 - normal.x*normal.x - normal.y * normal.y);
return normal;
#endif
}
float GetSpecularBlinn(float3 L, float3 N, float3 V, float gloss){
float shininess = exp2( gloss * 10.0 + 1.0);
float3 specular = float3(1,1,1);
float3 H = normalize(L + V);
specular *= pow( max(0, dot(H, N)), shininess);
return specular;
}
float GetSpecularPhong(float3 L, float3 N, float3 V, float gloss){
float shininess = exp2( gloss * 10.0 + 1.0);
float3 specular = float3(1,1,1);
specular *= pow( max(0, dot(R(-L, N), V)), shininess);
//if (dot(N, L) < 0.0){
// specular = float3(0.0, 0.0, 0.0);
//}
return specular;
}
half4 frag(g2f input) : SV_Target {
//MATRIX
float4x4 modelMatrix = unity_ObjectToWorld;
float4x4 modelMatrixInverse = unity_WorldToObject;
float3 tangentWorld = normalize( mul(modelMatrix, float4(input.tangent.xyz, 0.0)).xyz);
float3 normalWorld = normalize( mul(float4(input.normal, 0.0), modelMatrixInverse).xyz);
float3 binormalWorld = normalize( cross(normalWorld, tangentWorld) * input.tangent.w);
float3x3 tangentTransform = float3x3(tangentWorld, binormalWorld, normalWorld);
//TEXTURE
float4 mainTex = tex2D(_MainTex, input.uv);
float4 output = float4(1,1,1,1);
float3 normalLocal = unpack(tex2D(_Normal, input.uv));
//LIGHT
float3 L = normalize(_WorldSpaceLightPos0.xyz);
//float3 lightDir = normalize(_lightPos.xyz - input.worldPos.xyz);
//NORMAL
//float3 N = normalize(mul(normalLocal, tangentTransform));
float3 N = normalize(input.normal);
float NdotL = dot(N, L);
//CAMERA NORMAL
float3 V = normalize(_WorldSpaceCameraPos.xyz - input.worldPos.xyz);
float NdotV = max(dot(-N, V), dot(N, V));
//** DEPTH
float sceneZ = LinearEyeDepth (tex2Dproj(_CameraDepthTexture, UNITY_PROJ_COORD(input.projPos)).r);
float partZ = input.projPos.z;
float depth = clamp( pow((abs(sceneZ - partZ)) / _Threshold, 1), 0 , 1);
float silhouette = pow(depth, 1.3 - NdotL);
float furFuziness = clamp(mainTex.a + (_Fuziness - 0.5), 0,1);
float furRoot = pow(clamp( pow((abs(sceneZ - partZ)) / (1-_FurDepth), 1), 0 , 1), 1.3 - NdotL);
float furLight = clamp(mainTex.a - (_FurLight + 0.5), 0, 1);
//furLight = lerp(mainTex.a, furLight, silhouette);
//** COLOR
float3 light = NdotL * _LightColor0;
float3 diffuse = mainTex.rgb * light;
float3 specular = GetSpecularPhong(L, N, V, 0.5) * light;
output.rgb = lerp(mainTex.rgb, diffuse, _FurLight) + lerp(0, specular, _FurLight);
//** ALPHA
output.a = mainTex.a;
//**** DEPTH IMPROVEMENT
output.a = lerp(0, output.a, furRoot);
output.a = lerp(0, output.a, furFuziness);
//output.a = 0;
return output;
}
ENDCG
}
Pass {
Name "FORWARD_DELTA"
Tags {
"LightMode"="ForwardAdd"
}
Blend One One
ZWrite Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#define UNITY_PASS_FORWARDADD
#include "UnityCG.cginc"
#include "AutoLight.cginc"
#pragma multi_compile_fwdadd
#pragma multi_compile_fog
#pragma exclude_renderers gles3 metal d3d11_9x xbox360 xboxone ps3 ps4 psp2
#pragma target 3.0
uniform float4 _LightColor0;
uniform sampler2D _MainTex; uniform float4 _MainTex_ST;
struct VertexInput {
float4 vertex : POSITION;
float3 normal : NORMAL;
float2 texcoord0 : TEXCOORD0;
};
struct VertexOutput {
float4 pos : SV_POSITION;
float2 uv0 : TEXCOORD0;
float4 posWorld : TEXCOORD1;
float3 normalDir : TEXCOORD2;
LIGHTING_COORDS(3,4)
UNITY_FOG_COORDS(5)
};
VertexOutput vert (VertexInput v) {
VertexOutput o = (VertexOutput)0;
o.uv0 = v.texcoord0;
o.normalDir = UnityObjectToWorldNormal(v.normal);
o.posWorld = mul(unity_ObjectToWorld, v.vertex);
float3 lightColor = _LightColor0.rgb;
o.pos = UnityObjectToClipPos(v.vertex );
UNITY_TRANSFER_FOG(o,o.pos);
TRANSFER_VERTEX_TO_FRAGMENT(o)
return o;
}
float4 frag(VertexOutput i) : COLOR {
i.normalDir = normalize(i.normalDir);
float3 normalDirection = i.normalDir;
float4 _MainTex_var = tex2D(_MainTex,TRANSFORM_TEX(i.uv0, _MainTex));
clip(_MainTex_var.a - 0.5);
float3 lightDirection = normalize(lerp(_WorldSpaceLightPos0.xyz, _WorldSpaceLightPos0.xyz - i.posWorld.xyz,_WorldSpaceLightPos0.w));
float3 lightColor = _LightColor0.rgb;
////// Lighting:
float attenuation = LIGHT_ATTENUATION(i);
float3 attenColor = attenuation * _LightColor0.xyz;
/////// Diffuse:
float NdotL = max(0.0,dot( normalDirection, lightDirection ));
float3 directDiffuse = max( 0.0, NdotL) * attenColor;
float3 diffuseColor = _MainTex_var.rgb;
float3 diffuse = directDiffuse * diffuseColor;
/// Final Color:
float3 finalColor = diffuse;
fixed4 finalRGBA = fixed4(finalColor * _MainTex_var.a,0);
UNITY_APPLY_FOG(i.fogCoord, finalRGBA);
return finalRGBA;
}
ENDCG
}
Pass {
Name "ShadowCaster"
Tags {
"LightMode"="ShadowCaster"
}
Offset 1, 1
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#define UNITY_PASS_SHADOWCASTER
#include "UnityCG.cginc"
#include "Lighting.cginc"
#pragma fragmentoption ARB_precision_hint_fastest
#pragma multi_compile_shadowcaster
#pragma multi_compile_fog
#pragma exclude_renderers gles3 metal d3d11_9x xbox360 xboxone ps3 ps4 psp2
#pragma target 3.0
uniform sampler2D _MainTex;
uniform float4 _MainTex_ST;
uniform float _Cutoff;
struct VertexInput {
float4 vertex : POSITION;
float2 texcoord0 : TEXCOORD0;
};
struct VertexOutput {
V2F_SHADOW_CASTER;
float2 uv0 : TEXCOORD1;
};
VertexOutput vert (VertexInput v) {
VertexOutput o = (VertexOutput)0;
o.uv0 = v.texcoord0;
o.pos = UnityObjectToClipPos(v.vertex );
TRANSFER_SHADOW_CASTER(o)
return o;
}
float4 frag(VertexOutput i) : COLOR {
float4 _MainTex_var = tex2D(_MainTex,TRANSFORM_TEX(i.uv0, _MainTex));
clip(_MainTex_var.a - (1-_Cutoff));
SHADOW_CASTER_FRAGMENT(i)
}
ENDCG
}
}
//FallBack "Diffuse"
}