Created
August 18, 2023 21:10
-
-
Save farism/0ccd67dcd20deb39a4bc5073eda617a4 to your computer and use it in GitHub Desktop.
viewcone shader
This file contains hidden or 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
// 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