@@ -37,6 +37,83 @@ Texture2D g_BaseColor;
3737Texture2D g_PreintegratedGGX;
3838SamplerState g_PreintegratedGGX_sampler;
3939
40+ #if VIEW_MODE == VIEW_MODE_EDGE_MAP
41+ float ComputeColorEdge(int2 Pos)
42+ {
43+ int Width, Height;
44+ g_ColorBuffer.GetDimensions(Width, Height);
45+
46+ // t * * *
47+ // * * *
48+ // b * * *
49+ // l r
50+ int l = max(Pos.x - 1, 0);
51+ int b = max(Pos.y - 1, 0);
52+ int r = min(Pos.x + 1, Width - 1);
53+ int t = min(Pos.y + 1, Height - 1);
54+
55+ float3 LB = g_ColorBuffer.Load(int3(l, b, 0)).rgb;
56+ float3 RB = g_ColorBuffer.Load(int3(r, b, 0)).rgb;
57+ float3 LT = g_ColorBuffer.Load(int3(l, t, 0)).rgb;
58+ float3 RT = g_ColorBuffer.Load(int3(r, t, 0)).rgb;
59+
60+ float3 LL = g_ColorBuffer.Load(int3(l, Pos.y, 0)).rgb;
61+ float3 RR = g_ColorBuffer.Load(int3(r, Pos.y, 0)).rgb;
62+ float3 BB = g_ColorBuffer.Load(int3(Pos.x, b, 0)).rgb;
63+ float3 TT = g_ColorBuffer.Load(int3(Pos.x, t, 0)).rgb;
64+
65+ float3 H = (RR - LL) * 0.5;
66+ float3 V = (TT - BB) * 0.5;
67+ float3 D0 = (RT - LB) * 0.5;
68+ float3 D1 = (LT - RB) * 0.5;
69+
70+ float MaxGrad = max(max(length(H), length(V)), max(length(D0), length(D1)));
71+
72+ float Threshold = 0.2;
73+ float Scale = 5.0;
74+ return saturate((MaxGrad - Threshold) / (1.0 - Threshold) * Scale);
75+ }
76+
77+ float ComputeDepthEdge(int2 Pos, float Depth)
78+ {
79+ int Width, Height;
80+ g_Depth.GetDimensions(Width, Height);
81+
82+ // t * * *
83+ // * * *
84+ // b * * *
85+ // l r
86+ int l = max(Pos.x - 1, 0);
87+ int b = max(Pos.y - 1, 0);
88+ int r = min(Pos.x + 1, Width - 1);
89+ int t = min(Pos.y + 1, Height - 1);
90+
91+ float Z = DepthToCameraZ(Depth, g_Frame.Camera.mProj);
92+
93+ float LB = DepthToCameraZ(g_Depth.Load(int3(l, b, 0)).r, g_Frame.Camera.mProj);
94+ float RB = DepthToCameraZ(g_Depth.Load(int3(r, b, 0)).r, g_Frame.Camera.mProj);
95+ float LT = DepthToCameraZ(g_Depth.Load(int3(l, t, 0)).r, g_Frame.Camera.mProj);
96+ float RT = DepthToCameraZ(g_Depth.Load(int3(r, t, 0)).r, g_Frame.Camera.mProj);
97+
98+ float LL = DepthToCameraZ(g_Depth.Load(int3(l, Pos.y, 0)).r, g_Frame.Camera.mProj);
99+ float RR = DepthToCameraZ(g_Depth.Load(int3(r, Pos.y, 0)).r, g_Frame.Camera.mProj);
100+ float BB = DepthToCameraZ(g_Depth.Load(int3(Pos.x, b, 0)).r, g_Frame.Camera.mProj);
101+ float TT = DepthToCameraZ(g_Depth.Load(int3(Pos.x, t, 0)).r, g_Frame.Camera.mProj);
102+
103+ float H = abs(RR - LL) * 0.5;
104+ float V = abs(TT - BB) * 0.5;
105+ float D0 = abs(RT - LB) * 0.5;
106+ float D1 = abs(LT - RB) * 0.5;
107+
108+ float MaxGrad = max(max(H, V), max(D0, D1));
109+
110+ // Note: lower threshold makes planes at steep angles detected as edges
111+ float Threshold = 0.1;
112+ float Scale = 10.0;
113+ return saturate((abs(MaxGrad / Z) - Threshold) / (1.0 - Threshold) * Scale);
114+ }
115+ #endif
116+
40117void main(in FullScreenTriangleVSOutput VSOut,
41118 out float4 Color : SV_Target0)
42119{
@@ -100,8 +177,24 @@ void main(in FullScreenTriangleVSOutput VSOut,
100177 Color.rgb = ToneMap(Color.rgb, g_Attribs.ToneMapping, g_Attribs.AverageLogLum * exp2(-g_Frame.Camera.fExposure));
101178#endif
102179
180+ float Depth = g_Depth.Load(int3(Pos.xy, 0)).r;
181+
182+ #if VIEW_MODE == VIEW_MODE_EDGE_MAP
183+ {
184+ // Note that in the edge map mode, the scene is rendered with mesh normal debug view.
185+ float ColorEdgeFactor = ComputeColorEdge(int2(Pos.xy));
186+ if (Depth == g_Frame.Camera.fFarPlaneDepth)
187+ {
188+ // Don't detect color edges on the background
189+ ColorEdgeFactor = 0.0;
190+ }
191+ float DepthEdgeFactor = ComputeDepthEdge(int2(Pos.xy), Depth);
192+ float EdgeFactor = min(ColorEdgeFactor + DepthEdgeFactor, 1.0);
193+ Color.rgb = float3(EdgeFactor, EdgeFactor, EdgeFactor);
194+ }
195+ #endif
196+
103197 float SelectionDepth = g_SelectionDepth.Load(int3(Pos.xy, 0)).r;
104- float Depth = g_Depth.Load(int3(Pos.xy, 0)).r;
105198 bool IsSelected = Depth != g_Attribs.ClearDepth && SelectionDepth == Depth;
106199
107200 // Desaturate all unselected pixels
0 commit comments