// Unity built-in shader source. Copyright (c) 2023 Unity Technologies. MIT license (see license.txt) #ifndef SPEEDTREE_COMMON_INCLUDED #define SPEEDTREE_COMMON_INCLUDED float3 DoLeafFacing(float3 vPos, float3 anchor) { float3 facingPosition = vPos - anchor; // move to origin float offsetLen = length(facingPosition); // rotate X -90deg: normals keep looking 'up' while cards/leaves now 'stand up' and face the view plane facingPosition = float3(facingPosition.x, -facingPosition.z, facingPosition.y); // extract scale from model matrix float3x3 modelMatrix = (float3x3) GetObjectToWorldMatrix(); // UNITY_MATRIX_M float3 scale = float3( length(float3(modelMatrix[0][0], modelMatrix[1][0], modelMatrix[2][0])), length(float3(modelMatrix[0][1], modelMatrix[1][1], modelMatrix[2][1])), length(float3(modelMatrix[0][2], modelMatrix[1][2], modelMatrix[2][2])) ); // inverse of model : discards object rotations & scale // inverse of view : discards camera rotations float3x3 modelMatrixInv = (float3x3) GetWorldToObjectMatrix(); // UNITY_MATRIX_I_M float3x3 viewMatrixInv = (float3x3) GetViewToWorldMatrix(); // UNITY_MATRIX_I_V float3x3 matCardFacingTransform = mul(modelMatrixInv, viewMatrixInv); // re-encode the scale into the final transformation (otherwise cards would look small if tree is scaled up via world transform) matCardFacingTransform[0] *= scale.x; matCardFacingTransform[1] *= scale.y; matCardFacingTransform[2] *= scale.z; // make the leaves/cards face the camera facingPosition = mul(matCardFacingTransform, facingPosition.xyz); facingPosition = normalize(facingPosition) * offsetLen; // make sure the offset vector is still scaled return facingPosition + anchor; // move back to branch } #define SPEEDTREE_SUPPORT_NON_UNIFORM_SCALING 0 float3 TransformWindVectorFromWorldToLocalSpace(float3 vWindDirection) { // we intend to transform the world-space wind vector into local space. float3x3 modelMatrixInv = (float3x3) GetWorldToObjectMatrix(); // UNITY_MATRIX_I_M #if SPEEDTREE_SUPPORT_NON_UNIFORM_SCALING // the inverse world matrix would contain scale transformation as well, so we need // to get rid of scaling of the wind direction while doing inverse rotation. float3x3 modelMatrix = (float3x3) GetObjectToWorldMatrix(); // UNITY_MATRIX_M float3 scaleInv = float3( length(float3(modelMatrix[0][0], modelMatrix[1][0], modelMatrix[2][0])), length(float3(modelMatrix[0][1], modelMatrix[1][1], modelMatrix[2][1])), length(float3(modelMatrix[0][2], modelMatrix[1][2], modelMatrix[2][2])) ); float3x3 matWorldToLocalSpaceRotation = float3x3( // 3x3 discards translation modelMatrixInv[0][0] * scaleInv.x, modelMatrixInv[0][1] , modelMatrixInv[0][2], modelMatrixInv[1][0] , modelMatrixInv[1][1] * scaleInv.y, modelMatrixInv[1][2], modelMatrixInv[2][0] , modelMatrixInv[2][1] , modelMatrixInv[2][2] * scaleInv.z ); float3 vLocalSpaceWind = mul(matWorldToLocalSpaceRotation, vWindDirection); #else // Assume uniform scaling for the object -- discard translation and invert object rotations (and scale). // We'll normalize to get rid of scaling after the transformation. float3 vLocalSpaceWind = mul(modelMatrixInv, vWindDirection); #endif float windVecLength = length(vLocalSpaceWind); if (windVecLength > 1e-5) vLocalSpaceWind *= (1.0f / windVecLength); // normalize return vLocalSpaceWind; } #define ST_GEOM_TYPE_BRANCH 0 #define ST_GEOM_TYPE_FROND 1 #define ST_GEOM_TYPE_LEAF 2 #define ST_GEOM_TYPE_FACINGLEAF 3 int GetGeometryType(float4 uv3, out bool bLeafTwo) { int geometryType = (int) (uv3.w + 0.25); bLeafTwo = geometryType > ST_GEOM_TYPE_FACINGLEAF; if (bLeafTwo) { geometryType -= 2; } return geometryType; } // shadergraph stubs void SpeedTree8LeafFacing_float(float3 vVertexLocalPosition, float4 UV1, float4 UV2, float4 UV3, out float3 vVertexLocalPositionOut) { vVertexLocalPositionOut = vVertexLocalPosition; bool bDummy = false; if (GetGeometryType(UV3, bDummy) == ST_GEOM_TYPE_FACINGLEAF) { float3 vAnchorPosition = float3(UV1.zw, UV2.w); vVertexLocalPositionOut = DoLeafFacing(vVertexLocalPosition, vAnchorPosition); } } void SpeedTree9LeafFacing_float(float3 vVertexLocalPosition, float4 UV2, float4 UV3, out float3 vVertexLocalPositionOut) { vVertexLocalPositionOut = vVertexLocalPosition; const bool bHasCameraFacingLeaf = UV3.w > 0.0f || UV2.w > 0.0f; if (bHasCameraFacingLeaf) { const float3 vAnchorPosition = UV3.w > 0.0f ? UV3.xyz : UV2.xyz; vVertexLocalPositionOut = DoLeafFacing(vVertexLocalPosition, vAnchorPosition); } } void SpeedTreeLODTransition_float(float3 ObjectSpacePosition, float4 ObjectSpacePositionNextLOD, const bool bBillboard, out float3 OutObjectSpacePosition) { OutObjectSpacePosition = bBillboard ? ObjectSpacePosition : lerp(ObjectSpacePosition, ObjectSpacePositionNextLOD.xyz, unity_LODFade.x); } #endif // SPEEDTREE_COMMON_INCLUDED