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
|
#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "UnityPBSLighting.cginc"
#include "AutoLight.cginc"
struct appdata
{
float4 vertex: POSITION;
float3 normal: NORMAL;
float4 tangent: TANGENT;
float2 uv0: TEXCOORD0;
uint id: SV_VertexID;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct v2g
{
float4 pos: SV_POSITION;
float2 uv0: TEXCOORD0;
float3 normal: TEXCOORD4;
float3 tangent: TEXCOORD5;
uint vid: TEXCOORD6;
float3 worldPos: TEXCOORD7;
float3 binormal: TEXCOORD8;
UNITY_VERTEX_INPUT_INSTANCE_ID
UNITY_VERTEX_OUTPUT_STEREO
};
struct g2f
{
float4 pos: SV_POSITION;
float4 uv: TEXCOORD0;
float3 worldPos: TEXCOORD1;
float3 normal: TEXCOORD4;
float3 tangent: TEXCOORD5;
float startToEndGradient: TEXCOORD6;
UNITY_VERTEX_INPUT_INSTANCE_ID
UNITY_VERTEX_OUTPUT_STEREO
};
float3 CreateBinormal(float3 normal, float3 tangent, float binormalSign)
{
return cross(normal, tangent.xyz) *
(binormalSign * unity_WorldTransformParams.w);
}
v2g furVert(appdata v)
{
v2g o;
UNITY_SETUP_INSTANCE_ID(v);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
UNITY_TRANSFER_INSTANCE_ID(v, o);
o.worldPos = mul(unity_ObjectToWorld, v.vertex);
o.pos = UnityObjectToClipPos(v.vertex);
o.normal = UnityObjectToWorldNormal(v.normal);
o.tangent = UnityObjectToWorldDir(v.tangent.xyz);
o.binormal = CreateBinormal(o.normal, o.tangent, v.tangent.w);
o.uv0 = v.uv0.xy;
o.vid = v.id;
return o;
}
float random(float2 vids)
{
return frac(sin(dot(vids, float2(12.9898, 78.2383))) * 43758.5453123);
}
sampler2D _FurCombMap; float4 _FurCombMap_ST;
float _FurWidth;
float _FurCardLength;
float _FurRaised;
#include "PoiMath.cginc"
[maxvertexcount(6)]
void furGeom(triangle v2g IN[3], inout TriangleStream < g2f > tristream)
{
float randomValueA = random(float2(IN[0].vid + IN[2].vid, IN[2].vid + IN[0].vid));
float randomValueB = random(float2(IN[1].vid + IN[2].vid, IN[1].vid + IN[0].vid));
float randomValueC = random(float2(IN[2].vid + IN[2].vid, IN[0].vid + IN[0].vid));
float3 polySideA = IN[1].worldPos.xyz - IN[0].worldPos.xyz;
float3 polySideB = IN[2].worldPos.xyz - IN[0].worldPos.xyz;
float3 c = cross(polySideA, polySideB);
float3 outDir = normalize(c);
float3 furRootPos = float4(IN[0].worldPos.xyz + (polySideA * randomValueA) + (polySideB * randomValueB), 1);
float3 rootTangent = normalize((IN[0].tangent + IN[1].tangent + IN[2].tangent) * .3333333);
float3 rootNormal = normalize((IN[0].normal + IN[1].normal + IN[2].normal) * .3333333);
float3 rootBinormal = normalize((IN[0].binormal + IN[1].binormal + IN[2].binormal) * .3333333);
float3 furRight = normalize(cross(IN[0].binormal, outDir));
float2 rootUV = (IN[0].uv0 + IN[1].uv0 + IN[2].uv0) * .333333;
half3 tangentSpaceNormal = UnpackNormal(tex2Dlod(_FurCombMap, float4(TRANSFORM_TEX(rootUV, _FurCombMap), 0, 0)));
float3 furForward = normalize(
tangentSpaceNormal.x * rootTangent +
tangentSpaceNormal.y * rootBinormal +
tangentSpaceNormal.z * rootNormal
);
furForward = (lerp(furForward, outDir, _FurRaised));
//furForward = rotate_with_quaternion(furForward, float3(_FurRaised,0,0));
g2f o;
float4 worldPos[4];
float4 pos[4];
float4 uv[4];
uv[0] = float4(0, 0, rootUV);
uv[1] = float4(0, 1, rootUV);
uv[2] = float4(1, 1, rootUV);
uv[3] = float4(1, 0, rootUV);
_FurWidth *= .01;
_FurCardLength *= .01;
worldPos[3] = mul(unity_WorldToObject, float4(furRootPos + (furRight * _FurWidth) + (furForward * _FurCardLength), 1));
worldPos[2] = mul(unity_WorldToObject, float4(furRootPos + (furRight * _FurWidth), 1));
worldPos[1] = mul(unity_WorldToObject, float4(furRootPos + (-furRight * _FurWidth), 1));
worldPos[0] = mul(unity_WorldToObject, float4(furRootPos + (-furRight * _FurWidth) + (furForward * _FurCardLength), 1));
pos[3] = UnityObjectToClipPos(worldPos[3]);
pos[2] = UnityObjectToClipPos(worldPos[2]);
pos[1] = UnityObjectToClipPos(worldPos[1]);
pos[0] = UnityObjectToClipPos(worldPos[0]);
o.normal = rootNormal;
o.tangent = furForward;
o.worldPos = worldPos[0];
o.pos = pos[0];
o.uv = uv[0];
o.startToEndGradient = 1;
tristream.Append(o);
o.worldPos = worldPos[1];
o.pos = pos[1];
o.uv = uv[1];
o.startToEndGradient = 0;
tristream.Append(o);
o.worldPos = worldPos[2];
o.pos = pos[2];
o.uv = uv[2];
o.startToEndGradient = 0;
tristream.Append(o);
tristream.RestartStrip();
o.worldPos = worldPos[2];
o.pos = pos[2];
o.uv = uv[2];
o.startToEndGradient = 0;
tristream.Append(o);
o.worldPos = worldPos[3];
o.pos = pos[3];
o.uv = uv[3];
o.startToEndGradient = 1;
tristream.Append(o);
o.worldPos = worldPos[0];
o.pos = pos[0];
o.uv = uv[0];
o.startToEndGradient = 1;
tristream.Append(o);
tristream.RestartStrip();
}
sampler2D _FurCardTexture; float4 _FurCardTexture_ST; float4 _FurCardTexture_TexelSize;
sampler2D _FurCardAlphaTexture; float4 _FurCardAlphaTexture_ST; float4 _FurCardAlphaTexture_TexelSize;
sampler2D _FurPattern; float4 _FurPattern_ST;
float _FurClip;
fixed _FurAoStrength;
float CalcMipLevel(float2 uv)
{
float2 dx = ddx(uv * _FurCardTexture_TexelSize.zw);
float2 dy = ddy(uv * _FurCardTexture_TexelSize.zw);
float delta_max_sqr = max(dot(dx, dx), dot(dy, dy));
return max(0.0, 0.5 * log2(delta_max_sqr));
}
#include "CGI_FurLighting.cginc"
void ApplyAlphaToCoverage(inout float4 finalColor, float2 uv)
{
// rescale alpha by mip level (if not using preserved coverage mip maps)
finalColor.a *= 1 + max(0, CalcMipLevel(uv)) * .25;
// rescale alpha by partial derivative
finalColor.a = (finalColor.a - _FurClip) / fwidth(finalColor.a) + 0.5;
}
fixed4 FurFag(g2f i): SV_Target
{
float3 viewDir = normalize(_WorldSpaceCameraPos - i.worldPos);
UNITY_SETUP_INSTANCE_ID(i);
float4 finalColor = 1;
finalColor.rgb = tex2D(_FurPattern, TRANSFORM_TEX(i.uv.zw, _FurPattern)).rgb;
finalColor.rgb *= tex2D(_FurCardTexture, TRANSFORM_TEX(i.uv.xy, _FurCardTexture)).rgb;
finalColor.a = tex2D(_FurCardAlphaTexture, TRANSFORM_TEX(i.uv.xy, _FurCardAlphaTexture)).r;
ApplyAlphaToCoverage(finalColor, i.uv.xy);
applyFurLighting(finalColor, i.uv, 1 /*attenuation*/, i.normal, viewDir, i.worldPos);
finalColor.rgb *= lerp(1, i.startToEndGradient, _FurAoStrength);
return finalColor;
}
|