Skip to content

Instantly share code, notes, and snippets.

@farism
Created August 18, 2023 21:10
Show Gist options
  • Save farism/0ccd67dcd20deb39a4bc5073eda617a4 to your computer and use it in GitHub Desktop.
Save farism/0ccd67dcd20deb39a4bc5073eda617a4 to your computer and use it in GitHub Desktop.
viewcone shader
// gray = fully occluded, no enemy visibility. vertical occlusion occurs at < -4 and > +4 units.
// green = full enemy visibilty. 0 to 5 units horizontal range. -4 to 0 units vertical range.
// half green = partial enemy visibility. 5 to 30 units horizontal range. 0 to +4 units vertical range
Shader "Custom/Viewcone" {
Properties{
_Color("Color of viewcone",Color) = (1,1,1,1)
_Color2("Secondary color of viewcone",Color) = (1,1,1,1)
_WarningColor("Color of viewcone when detected",Color) = (1,1,1,1)
_AlertColor("Color of viewcone danger area",Color) = (1,1,1,1)
_OccludedColor("Color of occluded cone",Color) = (0,0,0,1)
_ViewAngle("View angle", Range(0.01,90)) = 60
_FarViewDistance("Far view distance", Range(2,100)) = 35
_NearViewDistance("Near view distance", Range(1,100)) = 15
_OriginY("Origin Y", float) = 0
_AlertScale("Alert scale", Range(0,1)) = 0
_IsAttacking("Viewcone owner is attacking", float) = 0
_Mask("Mask", 2D) = "white" {}
}
Subshader{
Tags{
"Queue" = "Transparent"
"RenderType" = "Transparent"
"RenderPipeline" = "UniversalRenderPipeline"
}
Pass {
Name "Unlit"
Cull Front
ZTest Always
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl"
struct appdata_base
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float4 pos : SV_POSITION;
float3 ray : TEXCOORD1;
float4 screenUV : TEXCOORD2;
float2 uv : TEXCOORD3;
};
TEXTURE2D_X_FLOAT( _ViewDepthTexture);
SAMPLER(sampler_ViewDepthTexture);
TEXTURE2D_X_FLOAT( _ViewDepthTextureLow);
SAMPLER(sampler_ViewDepthTextureLow);
sampler2D _Mask;
float4x4 _ViewSpaceMatrix;
float4x4 _ViewSpaceMatrixLow;
float3 _Test;
half4 _Color;
half4 _Color2;
half4 _WarningColor;
half4 _AlertColor;
half4 _OccludedColor;
half _ViewAngle;
half _FarViewDistance;
half _NearViewDistance;
half _OriginY;
half _AlertScale;
half _IsAttacking;
v2f vert(appdata_base v)
{
v2f o;
VertexPositionInputs vertInputs = GetVertexPositionInputs(v.vertex.xyz);
o.pos = vertInputs.positionCS;
o.ray = vertInputs.positionVS * float3(1, 1, -1);
o.screenUV = vertInputs.positionNDC;
o.uv = v.uv;
return o;
}
float getObstacleAlpha(float4 worldPos)
{
const float BIAS = 0.0001;
float4 posViewSpace = mul(_ViewSpaceMatrix, worldPos);
float3 projCoords = posViewSpace.xyz / posViewSpace.w; // ndc : -1 to 1
projCoords = projCoords * 0.5 + 0.5; // 0 to 1
float sampledDepth = (1.0 - SAMPLE_DEPTH_TEXTURE(_ViewDepthTexture, sampler_ViewDepthTexture, projCoords.xy));
float depthDiff = (projCoords.z - BIAS) - sampledDepth;
return depthDiff > 0 ? 0 : 1;
}
float getObstacleLowAlpha(float4 worldPos)
{
const float BIAS = 0.0001;
float4 posViewSpace = mul(_ViewSpaceMatrixLow, worldPos);
float3 projCoords = posViewSpace.xyz / posViewSpace.w; // ndc : -1 to 1
projCoords = projCoords * 0.5 + 0.5; // 0 to 1
float sampledDepth = (1.0 - SAMPLE_DEPTH_TEXTURE(_ViewDepthTextureLow, sampler_ViewDepthTextureLow, projCoords.xy));
float depthDiff = (projCoords.z - BIAS) - sampledDepth;
return depthDiff > 0 ? 0 : 1;
}
half4 frag(v2f i) : COLOR
{
i.ray = i.ray * (_ProjectionParams.z / i.ray.z);
float depth = Linear01Depth(SampleSceneDepth(i.screenUV.xy / i.screenUV.w), _ZBufferParams);
float4 vpos = float4(i.ray * depth, 1);
float4 wpos = mul(unity_CameraToWorld, vpos);
float3 opos = mul(unity_WorldToObject, wpos);
float3 oposclip = opos.xyz;
oposclip.y = 0;
clip(float3(0.5, 0.5, 0.5) - abs(oposclip));
clip((dot(normalize(ddy(wpos.xyz)), float3(0, 1, 0)) > 0.45) ? -1 : 1);
float len = length(opos.xz);
float nearLen = (_NearViewDistance / _FarViewDistance) * 0.5;
float fwdDotPos = max(dot(float2(0, 1), normalize(opos.xz)), 0);
float rangeAlpha = len < 0.01 || len > 0.5 ? 0 : 1; // alpha within range
float angleAlpha = acos(fwdDotPos) < radians(_ViewAngle / 2) ? 1 : 0; // alpha within view angle
float maskAlpha = tex2D(_Mask, opos.xz + float2(-0.5, -0.5)).a; // sample mask texture alpha
float alpha = rangeAlpha * angleAlpha;
float obstacleAlpha = getObstacleAlpha(wpos); // 0 if occluded, 1 if not
// float obstacleLowAlpha = getObstacleLowAlpha(wpos); // 0 if occluded, 1 if not
float4 col = _OccludedColor;
if (alpha > 0 && obstacleAlpha == 1) {
if (wpos.y >= _OriginY - 11.9 && wpos.y <= _OriginY + 3.9) {
if (_AlertScale > 0 && len < _AlertScale) {
col = _IsAttacking ? _AlertColor : _WarningColor;
} else if (len > nearLen) {
col = _Color2;
} else {
col = _Color;
}
}
if (len > nearLen || (wpos.y >= _OriginY + 2.9 && wpos.y <= _OriginY + 3.9)) {
col.a *= maskAlpha;
}
}
return float4(col.rgb, col.a * alpha);
}
ENDHLSL
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment