Created
May 3, 2024 19:02
-
-
Save Chaosed0/ecf85881be5dcb375373ccf48e776e11 to your computer and use it in GitHub Desktop.
Unity Shader helper for sorting 2D billboarded sprites against 3D objects
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// The functions in this file are used to transform camera-facing billboards into vertical billboards | |
// such that the way the sprite on the billboard is rendered remains the same. | |
// This is done to avoid sorting issues with 3D objects. | |
// This code taken from here: https://forum.unity.com/threads/problem-solving-2d-billboard-sprites-clipping-into-3d-environment.680374/ | |
// Calculates intersection point of ray and plane. | |
float RayPlaneIntersection(float3 rayDir, float3 rayPos, float3 planeNormal, float3 planePos) | |
{ | |
float denom = dot(planeNormal, rayDir); | |
denom = max(denom, 0.000001); // avoid divide by zero | |
float3 diff = planePos - rayPos; | |
return dot(diff, planeNormal) / denom; | |
} | |
// Given the object position of a vertex on a billboarded plane, returns the object position | |
// of that vertex if the billboard were vertically upright. | |
float4 ObjectToUprightObjectPos(float4 pos, float3 objectWorldOrigin) | |
{ | |
float3 viewPos = UnityObjectToViewPos(pos); | |
// calculate distance to vertical billboard plane seen at this vertex's screen position | |
float3 planeNormal = normalize(float3(UNITY_MATRIX_V._m20, 0.0, UNITY_MATRIX_V._m22)); | |
float3 planePoint = objectWorldOrigin; | |
float3 rayStart = _WorldSpaceCameraPos.xyz; | |
float3 rayDir = -normalize(mul(UNITY_MATRIX_I_V, float4(viewPos.xyz, 1.0)).xyz - rayStart); // convert view to world, minus camera pos | |
float dist = RayPlaneIntersection(rayDir, rayStart, planeNormal, planePoint); | |
// calculate the vertical plane world position | |
return float4(rayStart + rayDir * dist, 1.0); | |
} | |
// Given the vertical-billboard-corrected object position of a vertex, returns the clip-space | |
// position of that vertex. | |
float4 UprightObjectToClipPos(float4 pos, float4 uprightObjectPos) | |
{ | |
float4 clipPos = UnityObjectToClipPos(pos); | |
// calculate the clip space z for vertical plane | |
float4 planeOutPos = mul(UNITY_MATRIX_VP, uprightObjectPos); | |
float newPosZ = planeOutPos.z / planeOutPos.w * clipPos.w; | |
// use the closest clip space z | |
#if defined(UNITY_REVERSED_Z) | |
clipPos.z = max(clipPos.z, newPosZ); | |
#else | |
clipPos.z = min(clipPos.z, newPosZ); | |
#endif | |
return clipPos; | |
} | |
// Given the object position of a vertex on a billboarded plane, returns the clip-space position | |
// of that vertex if the billboard were vertically upright. | |
// This function allows you to specify the world origin of the object, which is necessary for | |
// things like particle systems where unity_ObjectToWorld.m03_m13_m23 returns the world-space | |
// origin of the entire particle system rather than the individual particle. | |
float4 ObjectToUprightClipPos(float4 pos, float3 objectWorldOrigin) | |
{ | |
return UprightObjectToClipPos(pos, ObjectToUprightObjectPos(pos, objectWorldOrigin)); | |
} | |
// Given the object position of a vertex on a billboarded plane, returns the clip-space position | |
// of that vertex if the billboard were vertically upright. | |
float4 ObjectToUprightClipPos(float4 pos) | |
{ | |
float3 objectWorldOrigin = unity_ObjectToWorld._m03_m13_m23; | |
return ObjectToUprightClipPos(pos, objectWorldOrigin); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment