#ifndef CURVED_WORLD_INCLUDED #define CURVED_WORLD_INCLUDED // Bend frame: the camera view by default. PortalMeadow can pin it to a fixed world-space frame // (e.g. a portal) so the bend stays still while the world is only seen through that portal. float4x4 _CurvedWorldFrame, _CurvedWorldFrameInv; float _CurvedWorldFrameFixed; float3 CurvedWorldToFrame(float3 positionWS) { return _CurvedWorldFrameFixed > 0.5 ? mul(_CurvedWorldFrame, float4(positionWS, 1)).xyz : TransformWorldToView(positionWS); } float3 CurvedFrameToWorld(float3 positionFS) { return mul(_CurvedWorldFrameFixed > 0.5 ? _CurvedWorldFrameInv : UNITY_MATRIX_I_V, float4(positionFS, 1)).xyz; } float3 CurvedWorldDirToFrame(float3 directionWS) { return mul((float3x3)(_CurvedWorldFrameFixed > 0.5 ? _CurvedWorldFrame : UNITY_MATRIX_V), directionWS); } float3 CurvedFrameDirToWorld(float3 directionFS) { return mul((float3x3)(_CurvedWorldFrameFixed > 0.5 ? _CurvedWorldFrameInv : UNITY_MATRIX_I_V), directionFS); } // Shared by the ground and the grass; also usable as a Shader Graph custom function. void CurvedWorld_float(float3 PositionOS, float Curvature, float StartDistance, float HorizontalInfluence, float BendAngle, out float3 Out) { #ifdef SHADERGRAPH_PREVIEW Out = PositionOS; #else float3 positionVS = CurvedWorldToFrame(TransformObjectToWorld(PositionOS)); // Rotate the bend frame around the camera's forward axis (degrees). // 0 = down, 90 = right, 180 = up, 270 = left. float s, c; sincos(radians(BendAngle), s, c); float lateral = dot(positionVS.xy, float2(c, s)); float distanceFromCamera = max(0.0, -positionVS.z - StartDistance); float bend = (distanceFromCamera * distanceFromCamera + lateral * lateral * HorizontalInfluence) * Curvature; positionVS.xy += float2(s, -c) * bend; Out = TransformWorldToObject(CurvedFrameToWorld(positionVS)); #endif } // Preserve existing Shader Graph custom functions using the original signature. void CurvedWorld_float(float3 PositionOS, float Curvature, float StartDistance, float HorizontalInfluence, out float3 Out) { CurvedWorld_float(PositionOS, Curvature, StartDistance, HorizontalInfluence, 0, Out); } float3 CurvedWorldNormalVS(float3 positionVS, float3 normalVS, float Curvature, float StartDistance, float HorizontalInfluence, float BendAngle) { float s, c; sincos(radians(BendAngle), s, c); float lateral = dot(positionVS.xy, float2(c, s)); float3 gradient = 2 * Curvature * float3(HorizontalInfluence * lateral * float2(c, s), -max(0.0, -positionVS.z - StartDistance)); // Inverse transpose of the bend Jacobian; the gradient is perpendicular to its direction. return normalVS - gradient * dot(float2(s, -c), normalVS.xy); } #endif