Skip to content

Instantly share code, notes, and snippets.

@Chikanut
Last active September 20, 2022 01:22
Show Gist options
  • Star 15 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Chikanut/50bda6a18806d44e297cd349041e3a2f to your computer and use it in GitHub Desktop.
Save Chikanut/50bda6a18806d44e297cd349041e3a2f to your computer and use it in GitHub Desktop.
This is HLSL code of See Through feature, all parameters of shader must be globally seted.
float2 WorldToScreenPos(float3 pos){
pos = normalize(pos - _WorldSpaceCameraPos)*(_ProjectionParams.y + (_ProjectionParams.z - _ProjectionParams.y))+_WorldSpaceCameraPos;
float2 uv =0;
float3 toCam = mul(unity_WorldToCamera, pos);
float camPosZ = toCam.z;
float height = 2 * camPosZ / unity_CameraProjection._m11;
float width = _ScreenParams.x / _ScreenParams.y * height;
uv.x = (toCam.x + width / 2)/width;
uv.y = (toCam.y + height / 2)/width;
return uv;
}
//Set this with (Shader.SetGlobal...) global shader values
uniform float3 _PlayerPosition;
uniform float _SeeThroughPower;
uniform float _SeeThroughRadius;
uniform float _SeeThroughDistortionFrequency;
uniform float _SeeThroughBorderSize;
uniform float4 _SeeThroughBorderColor;
uniform float _SeeThroughBorderEmission;
uniform float _SeeThroughAlpha;
float DitheredAlpha(half transparency, float3 positionWS)
{
float2 positionCS = WorldToScreenPos(positionWS);
half alpha = transparency;
if(alpha < 1)
{
#if defined(_ALPHATEST_ON)
float DITHER_THRESHOLDS[16] =
{
1.0 / 17.0, 9.0 / 17.0, 3.0 / 17.0, 11.0 / 17.0,
13.0 / 17.0, 5.0 / 17.0, 15.0 / 17.0, 7.0 / 17.0,
4.0 / 17.0, 12.0 / 17.0, 2.0 / 17.0, 10.0 / 17.0,
16.0 / 17.0, 8.0 / 17.0, 14.0 / 17.0, 6.0 / 17.0
};
float2 uv = positionCS.xy;// / _ScaledScreenParams.xy;
uv *= _ScreenParams.xy;
uint index = (uint(uv.x) % 4) * 4 + uint(uv.y) % 4;
// Returns > 0 if not clipped, < 0 if clipped based
// on the dither
return alpha - DITHER_THRESHOLDS[index];
#endif
}
return alpha;
}
//Use this function, you should send here world space position and it will return mask. RGB is a color of rim, and A chanel is an alpha of your object.
void SeeThroughMask_float(float3 positionWS, out float4 mask)
{
mask = float4(0,0,0,1);
float3 camRight = mul((float3x3)unity_CameraToWorld, float3(1,0,0));
float3 camForward = mul((float3x3)unity_CameraToWorld, float3(0,0,1));
float2 playerScreenPos = WorldToScreenPos(_PlayerPosition);
float2 pointScreenPos = WorldToScreenPos(positionWS);
float3 playerPos = _PlayerPosition;
float3 pointPos = positionWS;
float power = (1-clamp(sin(distance(playerScreenPos, pointScreenPos)),0,1));
float frequency = _SeeThroughDistortionFrequency * power;
float2 noise = normalize(float2(sin(pointScreenPos.x*frequency),cos(pointScreenPos.y*frequency)) + float2(_SinTime.x,_CosTime.y))*0.02f * power;
float holeScreenSizeX = distance(playerScreenPos, WorldToScreenPos(_PlayerPosition + camRight * (_SeeThroughRadius*_SeeThroughPower)));
float gradient = 1-clamp(distance(playerScreenPos, pointScreenPos+noise)/holeScreenSizeX,0,1);
mask.a = step(gradient,_SeeThroughBorderSize);
mask.rgb += ((mask.a - (step(gradient,0))))*_SeeThroughBorderColor.rgb;
playerPos.y = pointPos.y = _WorldSpaceCameraPos.y;
float dist = distance(playerPos*camRight, pointPos*camRight);
float playerDistance = distance(playerPos - dist * camForward, _WorldSpaceCameraPos);
float pointDistance = distance(pointPos, _WorldSpaceCameraPos);
if(playerDistance <= pointDistance)
{
mask = float4(0,0,0,1);
}
mask.rgb *= _SeeThroughBorderEmission;
//If you dont want to use dithering effect, just delete this line
mask.a = DitheredAlpha(lerp(_SeeThroughAlpha,1,mask.a), positionWS);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment