yum-archive/2ner

A toon shader for Unity's BIRP.

git clone https://git.yummers.dev/yum-archive/2ner

yumbegin sketching out harnack tracer0bdd125

master
2.7 KiB66 linesraw
1#ifndef __FACE_ME_INC
2#define __FACE_ME_INC
3
4#include "cnlohr.cginc"
5#include "interpolators.cginc"
6
7#if defined(_FACE_ME)
8// Rotate the object's position and normal so that it always faces the camera.
9void face_me(inout appdata v) {
10  [branch]
11  if (_Face_Me_Enabled_Dynamic) {
12    float3 object_center = mul(unity_ObjectToWorld, float4(0, 0, 0, 1));
13    // Get forward axis of object coordinate system, i.e. the orientation of
14    // the hip bone.
15    // Then project it onto the xz plane.
16    float3 forward_axis = mul(unity_ObjectToWorld, float3(0, 0, 1));
17    forward_axis.y = 0;
18    forward_axis = normalize(forward_axis);
19    float4 worldPos = mul(unity_ObjectToWorld, v.vertex);
20    float3 rd = normalize(object_center - getCenterCamPos());
21    // We apply a factor of -1 to shift the result forward by a phase shift of pi.
22    float cos_t = -dot(normalize(rd.xz), forward_axis.xz);
23    // We want to get sin(t) using the identity:
24    //   || a x b || = || a || || b || sin(t)
25    // For normal vectors, this simplifies to:
26    //   || a x b || = sin(t)
27    // The issue is that the norm operator loses the sign.
28    // We can estimate the sign by assuming that `rd` and `forward_axis` are on
29    // the xz plane.
30    // If that's the case, then the cross product is necessarily constrained to
31    // the y axis.
32    float sin_t_sign = sign(cross(rd, forward_axis).y);
33    // Here we use the identity:
34    //   sin(t) = sqrt(1 - cos(t)^2)
35    // We simply apply the sign correction `sin_t_sign` to the result.
36    // We then invert it, since the goal is not to amplify the rotation, but
37    // to negate it.
38    // Finally, we add a phase correction to make the abomination face us.
39    float sin_t = -sqrt(1 - cos_t * cos_t) * sin_t_sign;
40
41    // Double the angle using double-angle formulas
42    if (isVR()) {
43        float sin_2t = 2 * sin_t * cos_t;
44        float cos_2t = cos_t * cos_t - sin_t * sin_t;  // or: 2 * cos_t * cos_t - 1
45        sin_t = sin_2t;
46        cos_t = cos_2t;
47    }
48
49    // Use the doubled angle values in your rotation matrix
50    float2x2 face_me_rot = float2x2(cos_t, -sin_t, sin_t, cos_t);
51    worldPos.xz = mul(face_me_rot, (worldPos.xz - object_center.xz)) + object_center.xz;
52    v.vertex = mul(unity_WorldToObject, worldPos);
53
54    float3 world_normal = UnityObjectToWorldNormal(v.normal);
55    world_normal.xz = mul(face_me_rot, world_normal.xz);
56    v.normal = normalize(mul(unity_WorldToObject, world_normal));
57
58    float3 world_tangent = UnityObjectToWorldDir(v.tangent.xyz);
59    world_tangent.xz = mul(face_me_rot, world_tangent.xz);
60    v.tangent.xyz = normalize(mul(unity_WorldToObject, world_tangent));
61  }
62}
63#endif  // _FACE_ME
64
65#endif  // __FACE_ME_INC
66