A game about forced loneliness, made by TACStudios
1// Unity built-in shader source. Copyright (c) 2023 Unity Technologies. MIT license (see license.txt)
2
3#ifndef SPEEDTREE_COMMON_INCLUDED
4#define SPEEDTREE_COMMON_INCLUDED
5
6
7float3 DoLeafFacing(float3 vPos, float3 anchor)
8{
9 float3 facingPosition = vPos - anchor; // move to origin
10 float offsetLen = length(facingPosition);
11
12 // rotate X -90deg: normals keep looking 'up' while cards/leaves now 'stand up' and face the view plane
13 facingPosition = float3(facingPosition.x, -facingPosition.z, facingPosition.y);
14
15 // extract scale from model matrix
16 float3x3 modelMatrix = (float3x3) GetObjectToWorldMatrix(); // UNITY_MATRIX_M
17 float3 scale = float3(
18 length(float3(modelMatrix[0][0], modelMatrix[1][0], modelMatrix[2][0])),
19 length(float3(modelMatrix[0][1], modelMatrix[1][1], modelMatrix[2][1])),
20 length(float3(modelMatrix[0][2], modelMatrix[1][2], modelMatrix[2][2]))
21 );
22
23 // inverse of model : discards object rotations & scale
24 // inverse of view : discards camera rotations
25 float3x3 modelMatrixInv = (float3x3) GetWorldToObjectMatrix(); // UNITY_MATRIX_I_M
26 float3x3 viewMatrixInv = (float3x3) GetViewToWorldMatrix(); // UNITY_MATRIX_I_V
27 float3x3 matCardFacingTransform = mul(modelMatrixInv, viewMatrixInv);
28
29 // re-encode the scale into the final transformation (otherwise cards would look small if tree is scaled up via world transform)
30 matCardFacingTransform[0] *= scale.x;
31 matCardFacingTransform[1] *= scale.y;
32 matCardFacingTransform[2] *= scale.z;
33
34 // make the leaves/cards face the camera
35 facingPosition = mul(matCardFacingTransform, facingPosition.xyz);
36 facingPosition = normalize(facingPosition) * offsetLen; // make sure the offset vector is still scaled
37
38 return facingPosition + anchor; // move back to branch
39}
40
41#define SPEEDTREE_SUPPORT_NON_UNIFORM_SCALING 0
42float3 TransformWindVectorFromWorldToLocalSpace(float3 vWindDirection)
43{
44 // we intend to transform the world-space wind vector into local space.
45 float3x3 modelMatrixInv = (float3x3) GetWorldToObjectMatrix(); // UNITY_MATRIX_I_M
46#if SPEEDTREE_SUPPORT_NON_UNIFORM_SCALING
47 // the inverse world matrix would contain scale transformation as well, so we need
48 // to get rid of scaling of the wind direction while doing inverse rotation.
49 float3x3 modelMatrix = (float3x3) GetObjectToWorldMatrix(); // UNITY_MATRIX_M
50 float3 scaleInv = float3(
51 length(float3(modelMatrix[0][0], modelMatrix[1][0], modelMatrix[2][0])),
52 length(float3(modelMatrix[0][1], modelMatrix[1][1], modelMatrix[2][1])),
53 length(float3(modelMatrix[0][2], modelMatrix[1][2], modelMatrix[2][2]))
54 );
55 float3x3 matWorldToLocalSpaceRotation = float3x3( // 3x3 discards translation
56 modelMatrixInv[0][0] * scaleInv.x, modelMatrixInv[0][1] , modelMatrixInv[0][2],
57 modelMatrixInv[1][0] , modelMatrixInv[1][1] * scaleInv.y, modelMatrixInv[1][2],
58 modelMatrixInv[2][0] , modelMatrixInv[2][1] , modelMatrixInv[2][2] * scaleInv.z
59 );
60 float3 vLocalSpaceWind = mul(matWorldToLocalSpaceRotation, vWindDirection);
61#else
62 // Assume uniform scaling for the object -- discard translation and invert object rotations (and scale).
63 // We'll normalize to get rid of scaling after the transformation.
64 float3 vLocalSpaceWind = mul(modelMatrixInv, vWindDirection);
65#endif
66 float windVecLength = length(vLocalSpaceWind);
67 if (windVecLength > 1e-5)
68 vLocalSpaceWind *= (1.0f / windVecLength); // normalize
69 return vLocalSpaceWind;
70}
71
72#define ST_GEOM_TYPE_BRANCH 0
73#define ST_GEOM_TYPE_FROND 1
74#define ST_GEOM_TYPE_LEAF 2
75#define ST_GEOM_TYPE_FACINGLEAF 3
76int GetGeometryType(float4 uv3, out bool bLeafTwo)
77{
78 int geometryType = (int) (uv3.w + 0.25);
79 bLeafTwo = geometryType > ST_GEOM_TYPE_FACINGLEAF;
80 if (bLeafTwo)
81 {
82 geometryType -= 2;
83 }
84 return geometryType;
85}
86
87// shadergraph stubs
88void SpeedTree8LeafFacing_float(float3 vVertexLocalPosition, float4 UV1, float4 UV2, float4 UV3, out float3 vVertexLocalPositionOut)
89{
90 vVertexLocalPositionOut = vVertexLocalPosition;
91 bool bDummy = false;
92 if (GetGeometryType(UV3, bDummy) == ST_GEOM_TYPE_FACINGLEAF)
93 {
94 float3 vAnchorPosition = float3(UV1.zw, UV2.w);
95 vVertexLocalPositionOut = DoLeafFacing(vVertexLocalPosition, vAnchorPosition);
96 }
97}
98void SpeedTree9LeafFacing_float(float3 vVertexLocalPosition, float4 UV2, float4 UV3, out float3 vVertexLocalPositionOut)
99{
100 vVertexLocalPositionOut = vVertexLocalPosition;
101 const bool bHasCameraFacingLeaf = UV3.w > 0.0f || UV2.w > 0.0f;
102 if (bHasCameraFacingLeaf)
103 {
104 const float3 vAnchorPosition = UV3.w > 0.0f ? UV3.xyz : UV2.xyz;
105 vVertexLocalPositionOut = DoLeafFacing(vVertexLocalPosition, vAnchorPosition);
106 }
107}
108
109void SpeedTreeLODTransition_float(float3 ObjectSpacePosition, float4 ObjectSpacePositionNextLOD, const bool bBillboard, out float3 OutObjectSpacePosition)
110{
111 OutObjectSpacePosition = bBillboard
112 ? ObjectSpacePosition
113 : lerp(ObjectSpacePosition, ObjectSpacePositionNextLOD.xyz, unity_LODFade.x);
114}
115
116#endif // SPEEDTREE_COMMON_INCLUDED