[Optimization] Better implementation of Helpers.cginc : ApplyHue
OwenTheProgram
The function ApplyHue in Packages/com.vrchat.base/Runtime/VRCSDK/Sample Assets/Shaders/Mobile/ToonStandard/CG/Helpers.cginc
can be replaced by the following function, yielding 1:1 results.
// Rotates white-point to Z axis, rotates around Z, undo white-point rotation.
half3 ApplyHue(half3 col, half hueAngle, half mask)
{
UNITY_BRANCH
if (hueAngle == 0)
{
return col;
}
else
{
const half PI = 3.14159265359;
const half3 OFFSETS = PI * half3(0.0/3.0, 2.0/3.0, 4.0/3.0);
half3 ct = (1.0/3.0) + (2.0/3.0) * cos(hueAngle + OFFSETS);
half3 shifted = (col.rgb
ct.x) + (col.gbr
ct.y) + (col.brg * ct.z);return lerp(col, shifted, mask);
}
}
In my testing, the original ApplyHue function compiles to this:
0: sample r0.xyzw, v1.xyxx, t0.xyzw, s0
1: eq r0.w, cb0[2].x, l(0.000000)
2: if_nz r0.w
3: mov o0.xyz, r0.xyzx
4: else
5: sincos r1.x, r2.x, cb0[2].x
6: mul r1.yzw, r0.zzxy, l(0.000000, 0.577350, 0.577350, 0.577350)
7: mad r1.yzw, r0.zzxy, l(0.000000, 0.577350, 0.577350, 0.577350), -r1.wwyz
8: mul r1.xyz, r1.xxxx, r1.yzwy
9: mad r1.xyz, r0.xyzx, r2.xxxx, r1.xyzx
10: dp3 r0.w, l(0.577350, 0.577350, 0.577350, 0.000000), r0.xyzx
11: mul r0.w, r0.w, l(0.577350)
12: add r1.w, -r2.x, l(1.000000)
13: mad r1.xyz, r0.wwww, r1.wwww, r1.xyzx
14: add r1.xyz, -r0.xyzx, r1.xyzx
15: mad o0.xyz, v1.zzzz, r1.xyzx, r0.xyzx
16: endif
17: ret
while my function this compiles to this:
0: sample r0.xyzw, v1.xyxx, t0.xyzw, s0
1: eq r0.w, cb0[2].x, l(0.000000)
2: if_nz r0.w
3: mov o0.xyz, r0.xyzx
4: else
5: add r1.xyz, cb0[2].xxxx, l(0.000000, 2.094395, 4.188790, 0.000000)
6: sincos null, r1.xyz, r1.xyzx
7: mad r1.xyz, r1.xyzx, l(0.666667, 0.666667, 0.666667, 0.000000), l(0.333333, 0.333333, 0.333333, 0.000000)
8: mul r2.xyz, r0.yzxy, r1.yyyy
9: mad r1.xyw, r0.xyxz, r1.xxxx, r2.xyxz
10: mad r1.xyz, r0.zxyz, r1.zzzz, r1.xywx
11: add r1.xyz, -r0.xyzx, r1.xyzx
12: mad o0.xyz, v1.zzzz, r1.xyzx, r0.xyzx
13: endif
14: ret
Both functions use two temporary registers when I tested them in fragment.
Optionally
half3 ct = (1.0/3.0) + (2.0/3.0) * cos(hueAngle + OFFSETS);
can be replaced with
half3 ct = (1.0/3.0) + (2.0/3.0)
cos(hueAngle
UNITY_TWO_PI + OFFSETS);to resolve feedback like this one
I have made supplemental demos in Desmos to showcase the methods:
I hereby grant legal rights to all shader code presented in this feature request. I present all of the above, granting full rights to use, reuse, modify, redistribute, and will not persue any form of legal action, following the guidelines of the MIT-0 No Attribution licence. blablabla open source, use it as you wish!
ApplyHueMinimal.shader (which I have renamed to .txt for sending) has the MIT-0 licence as a header segment by the way.
Log In
OwenTheProgram
ah I forgot to mention as well, it may be wise to saturate the hue shifted colour, because rotating in both ways can result in non 0 to 1 ranges for red green and blue.