DDX/DDY
環境
Unity2021.2.18f1
概要
ddxとddyは勾配を取得する命令です。
引数で渡した変数のとなりのピクセル(厳密には違う)との差分が得られます。
以下のシェーダはデプスとノーマルのそれぞれの差分を取り、エッジ検出をしてそこにAA的な処理(ただぼかしているだけ)を施しています。
Shader "Hidden/PostDdxy" { Properties { _MainTex ("Texture", 2D) = "white" {} _EdgeNormal("Judge Edge Normal", float) = 0.99 _EdgeDepth("Judge Edge Depth", float) = 0.001 } SubShader { Cull Off ZWrite Off ZTest Always Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float4 vertex : SV_POSITION; float2 uv : TEXCOORD0; }; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = v.uv; return o; } sampler2D _MainTex; sampler2D _CameraDepthTexture; sampler2D _CameraDepthNormalsTexture; float _EdgeNormal; float _EdgeDepth; fixed3 antiAlias(v2f i, float3 rgb) { float2 offset = float2(1.0 - _ScreenParams.z, 1.0 - _ScreenParams.w); #if 0 float3 u = tex2D(_MainTex, i.uv + float2(0, offset.y)).rgb; float3 b = tex2D(_MainTex, i.uv + float2(0, -offset.y)).rgb; float3 l = tex2D(_MainTex, i.uv + float2(-offset.x, 0)).rgb; float3 r = tex2D(_MainTex, i.uv + float2(offset.x, 0)).rgb; rgb = (rgb + u + b + l + r) / 5.0; #else float3 rgb0 = tex2D(_MainTex, i.uv + float2( 0.0, offset.y)).rgb; float3 rgb1 = tex2D(_MainTex, i.uv + float2( 0.87 * offset.x, -0.50 * offset.y)).rgb; float3 rgb2 = tex2D(_MainTex, i.uv + float2(-0.87 * offset.x, -0.50 * offset.y)).rgb; rgb = (rgb + rgb0 + rgb1 + rgb2) / 4.0; #endif return rgb; } bool IsEdgeNormal(float2 uv) { float4 depthNormal = tex2D(_CameraDepthNormalsTexture, uv); float tempDepth; float3 normal; DecodeDepthNormal(depthNormal, tempDepth, normal); float3 diffNormalX = ddx(normal); float3 diffNormalY = ddy(normal); float3 normal2 = normal + (0 + diffNormalX + diffNormalY) / 3.0; float edgeNormal = dot(normal, normal2); return (edgeNormal < _EdgeNormal); } bool IsEdgeDepth(float2 uv) { float depth = LinearEyeDepth(tex2D(_CameraDepthTexture, uv).r) * _ProjectionParams.w; float edgeDepth = abs(ddx(depth)) + abs(ddy(depth)); return (edgeDepth > _EdgeDepth); } bool IsEdge(float2 uv) { return IsEdgeDepth(uv) || IsEdgeNormal(uv); } fixed4 frag(v2f i) : SV_Target { float2 offset = float2(1.0 - _ScreenParams.z, 1.0 - _ScreenParams.w); float4 col = tex2D(_MainTex, i.uv); if (IsEdge(i.uv) || IsEdge(i.uv + offset)) col.rgb = antiAlias(i, col.rgb); //else // col.rgb = 0.0; return col; } ENDCG } } }
using UnityEngine; public class PostDdxy : MonoBehaviour { [SerializeField] private Material _material = null; private void Start() { Camera.main.depthTextureMode |= DepthTextureMode.DepthNormals; } private void OnRenderImage(RenderTexture source, RenderTexture destination) { Graphics.Blit(source, destination, _material); } }