Skip to content

Commit 5de351f

Browse files
[HDRP][Compositor] Fix outlines in transitions between post-processed and plain regions (#1972)
* Add controls for the transition between post processed and plain image parts * Changelog Co-authored-by: sebastienlagarde <[email protected]>
1 parent 1b765c6 commit 5de351f

File tree

9 files changed

+121
-3
lines changed

9 files changed

+121
-3
lines changed

com.unity.render-pipelines.high-definition/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
128128
- Fixed error Maximum allowed thread group count is 65535 when resolution is very high.
129129
- LOD meshes are now properly stripped based on the maximum lod value parameters contained in the HDRP asset.
130130
- Fixed an inconsistency in the LOD group UI where LOD bias was not the right one.
131+
- Fixed outlines in transitions between post-processed and plain regions in the graphics compositor (case 1278775).
131132

132133
### Changed
133134
- Preparation pass for RTSSShadows to be supported by render graph.

com.unity.render-pipelines.high-definition/Editor/Compositor/CompositionLayerUI.Drawers.cs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ static partial class Styles
3030
static public readonly GUIContent k_AAMode = EditorGUIUtility.TrTextContent("Post Anti-aliasing", "To override the postprocess Anti-aliasing mode, activate the option by clicking on the check-box and then select the desired value.");
3131
static public readonly GUIContent k_CullingMask = EditorGUIUtility.TrTextContent("Culling Mask", "To override the culling mask, activate the option by clicking on the check-box and then select the desired value.");
3232
static public readonly GUIContent k_VolumeMask = EditorGUIUtility.TrTextContent("Volume Mask", "To override the volume mask, activate the option by clicking on the check-box and then select the desired value.");
33+
static public readonly GUIContent k_AlphaRange = EditorGUIUtility.TrTextContent("Alpha Range", "The range of alpha values used when transitioning from post-processed to plain image regions. A smaller range will result in a steeper transition.");
3334

3435
static public readonly string k_AlphaInfoPost = "The use of AOVs properties in a player require to to enable the Runtime AOV API support in the HDRP quality settings.";
3536

@@ -178,6 +179,58 @@ public static void DrawStackedLayerProperties(Rect rect, SerializedCompositionLa
178179
rect.y += CompositorStyle.k_Spacing;
179180

180181
EditorGUI.PropertyField(rect, serializedProperties.clearAlpha, Styles.k_ClearAlpha);
182+
rect.y += 1.0f * CompositorStyle.k_Spacing;
183+
184+
// Draw a min/max slider for tha alpha range
185+
{
186+
const float spacing = 5;
187+
var labelRect = new Rect(rect.x, rect.y, EditorGUIUtility.labelWidth, rect.height);
188+
EditorGUI.PrefixLabel(labelRect, Styles.k_AlphaRange);
189+
190+
var minLabelRect = rect;
191+
minLabelRect.x += EditorGUIUtility.labelWidth;
192+
minLabelRect.width = EditorGUIUtility.fieldWidth / 2;
193+
serializedProperties.alphaMin.floatValue = EditorGUI.FloatField(minLabelRect, serializedProperties.alphaMin.floatValue);
194+
195+
GUI.SetNextControlName("AlphaMinMaxSlider");
196+
var sliderRect = rect;
197+
sliderRect.x += EditorGUIUtility.labelWidth + EditorGUIUtility.fieldWidth / 2 + spacing;
198+
sliderRect.width -= (EditorGUIUtility.labelWidth + EditorGUIUtility.fieldWidth + 2 * spacing);
199+
float minVal = serializedProperties.alphaMin.floatValue;
200+
float maxVal = serializedProperties.alphaMax.floatValue;
201+
202+
EditorGUI.MinMaxSlider(sliderRect, ref minVal, ref maxVal, 0, 1);
203+
if (serializedProperties.alphaMin.floatValue != minVal || serializedProperties.alphaMax.floatValue != maxVal)
204+
{
205+
// Note: We need to move the focus when the slider changes, otherwise the textField will not update
206+
GUI.FocusControl("AlphaMinMaxSlider");
207+
serializedProperties.alphaMin.floatValue = minVal;
208+
serializedProperties.alphaMax.floatValue = maxVal;
209+
}
210+
211+
var maxLabelRect = rect;
212+
maxLabelRect.x = sliderRect.x + sliderRect.width + spacing;
213+
maxLabelRect.width = EditorGUIUtility.fieldWidth / 2;
214+
serializedProperties.alphaMax.floatValue = EditorGUI.FloatField(maxLabelRect, serializedProperties.alphaMax.floatValue);
215+
216+
// sanity checks
217+
if (serializedProperties.alphaMax.floatValue < serializedProperties.alphaMin.floatValue)
218+
{
219+
serializedProperties.alphaMax.floatValue = serializedProperties.alphaMin.floatValue;
220+
}
221+
if (serializedProperties.alphaMax.floatValue > 1)
222+
{
223+
serializedProperties.alphaMax.floatValue = 1;
224+
}
225+
if (serializedProperties.alphaMin.floatValue > serializedProperties.alphaMax.floatValue)
226+
{
227+
serializedProperties.alphaMin.floatValue = serializedProperties.alphaMax.floatValue;
228+
}
229+
if (serializedProperties.alphaMin.floatValue < 0)
230+
{
231+
serializedProperties.alphaMin.floatValue = 0;
232+
}
233+
}
181234
rect.y += 1.5f * CompositorStyle.k_Spacing;
182235

183236
// The clear mode should be visible / configurable only for the first layer in the stack. For the other layers we set a camera-stacking specific clear-mode .

com.unity.render-pipelines.high-definition/Editor/Compositor/SerializedCompositionLayer.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ internal class SerializedCompositionLayer
3030
public SerializedProperty aovBitmask;
3131
public SerializedProperty inputFilters;
3232
public SerializedProperty positionInStack;
33+
public SerializedProperty alphaMin;
34+
public SerializedProperty alphaMax;
3335

3436
public List<SerializedCompositionFilter> filterList = new List<SerializedCompositionFilter>();
3537

@@ -60,6 +62,8 @@ public SerializedCompositionLayer(SerializedProperty root)
6062
aovBitmask = root.FindPropertyRelative("m_AOVBitmask");
6163
inputFilters = root.FindPropertyRelative("m_InputFilters");
6264
positionInStack = root.FindPropertyRelative("m_LayerPositionInStack");
65+
alphaMin = root.FindPropertyRelative("m_AlphaMin");
66+
alphaMax = root.FindPropertyRelative("m_AlphaMax");
6367

6468
for (int index = 0; index < inputFilters.arraySize; index++)
6569
{
@@ -91,7 +95,8 @@ public float GetPropertiesHeight()
9195
EditorGUI.GetPropertyHeight(cullingMaskProperty, null) +
9296
EditorGUI.GetPropertyHeight(volumeMask, null) +
9397
EditorGUI.GetPropertyHeight(inputFilters, null) +
94-
EditorGUIUtility.singleLineHeight * 7; //for the heading and pading
98+
EditorGUI.GetPropertyHeight(alphaMin, null) + // we use a min/max slider in the UI so it takes a sinle line, so we don't need to count the alphaMax
99+
EditorGUIUtility.singleLineHeight * 7; // for the heading and pading
95100

96101
if (inputFilters.arraySize > 0)
97102
{

com.unity.render-pipelines.high-definition/Runtime/Compositor/AdditionalCompositorData.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ internal class AdditionalCompositorData : MonoBehaviour
1717
public bool clearAlpha = true; // Clearing the alpha allows the post process to run only on the pixels covered by a stacked camera (and not the previous ones).
1818
public BackgroundFitMode imageFitMode = BackgroundFitMode.Stretch;
1919
public List<CompositionFilter> layerFilters;
20+
public float alphaMax = 1.0f;
21+
public float alphaMin = 0.0f;
2022

2123
public void Init(List<CompositionFilter> layerFilters, bool clearAlpha)
2224
{
@@ -36,6 +38,8 @@ public void ResetData()
3638
layerFilters = null;
3739
}
3840

41+
alphaMax = 1.0f;
42+
alphaMin = 0.0f;
3943
}
4044
}
4145
}

com.unity.render-pipelines.high-definition/Runtime/Compositor/CompositionLayer.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,10 @@ public float aspectRatio
136136
// Returns true if this layer is using a camera that was cloned internally for drawing
137137
bool isUsingACameraClone => !m_LayerCamera.Equals(m_Camera);
138138

139+
// The input alpha will be mapped between the min and max range when blending between the post-processed and plain image regions. This way the user can controls how steep is the transition.
140+
[SerializeField] float m_AlphaMin = 0.0f;
141+
[SerializeField] float m_AlphaMax = 1.0f;
142+
139143
private CompositorLayer()
140144
{
141145
}
@@ -469,6 +473,9 @@ public void SetAdditionalLayerData()
469473
if (layerData != null)
470474
{
471475
layerData.Init(m_InputFilters, m_ClearAlpha);
476+
477+
layerData.alphaMin = m_AlphaMin;
478+
layerData.alphaMax = m_AlphaMax;
472479
}
473480
}
474481
}
@@ -507,7 +514,7 @@ public void UpdateOutputCamera()
507514
if (m_Type == LayerType.Image)
508515
{
509516
var compositorData = m_LayerCamera.GetComponent<AdditionalCompositorData>();
510-
if(compositorData)
517+
if (compositorData)
511518
compositorData.clearColorTexture = (m_Show && m_InputTexture != null) ? m_InputTexture : Texture2D.blackTexture;
512519
}
513520

com.unity.render-pipelines.high-definition/Runtime/Compositor/CompositionManager.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -838,5 +838,28 @@ static public Camera GetSceceCamera()
838838
static public CompositionManager GetInstance() =>
839839
s_CompositorInstance ?? (s_CompositorInstance = GameObject.FindObjectOfType(typeof(CompositionManager), true) as CompositionManager);
840840

841+
static public Vector4 GetAlphaScaleAndBiasForCamera(HDCamera hdCamera)
842+
{
843+
AdditionalCompositorData compositorData = null;
844+
hdCamera.camera.TryGetComponent<AdditionalCompositorData>(out compositorData);
845+
846+
if (compositorData)
847+
{
848+
float alphaMin = compositorData.alphaMin;
849+
float alphaMax = compositorData.alphaMax;
850+
851+
if (alphaMax == alphaMin)
852+
alphaMax += 0.0001f; // Mathf.Epsilon is too small and in this case it creates precission issues
853+
854+
float alphaScale = 1.0f / (alphaMax - alphaMin);
855+
float alphaBias = -alphaMin * alphaScale;
856+
857+
return new Vector4(alphaScale, alphaBias, 0.0f, 0.0f);
858+
}
859+
860+
// No compositor-specific data for this camera/layer, just return the default/neutral scale and bias
861+
return new Vector4(1.0f, 0.0f, 0.0f, 0.0f);
862+
}
863+
841864
}
842865
}

com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -885,6 +885,8 @@ struct UberPostParameters
885885
public Vector4 bloomBicubicParams;
886886
public Vector4 bloomDirtTileOffset;
887887
public Vector4 bloomThreshold;
888+
889+
public Vector4 alphaScaleBias;
888890
}
889891

890892
UberPostParameters PrepareUberPostParameters(HDCamera hdCamera, bool isSceneView)
@@ -918,10 +920,23 @@ UberPostParameters PrepareUberPostParameters(HDCamera hdCamera, bool isSceneView
918920
PrepareChromaticAberrationParameters(ref parameters, featureFlags);
919921
PrepareVignetteParameters(ref parameters, featureFlags);
920922
PrepareUberBloomParameters(ref parameters, hdCamera);
923+
PrepareAlphaScaleParameters(ref parameters, hdCamera);
921924

922925
return parameters;
923926
}
924927

928+
void PrepareAlphaScaleParameters(ref UberPostParameters parameters, HDCamera camera)
929+
{
930+
if (m_EnableAlpha)
931+
{
932+
parameters.alphaScaleBias = Compositor.CompositionManager.GetAlphaScaleAndBiasForCamera(camera);
933+
}
934+
else
935+
{
936+
parameters.alphaScaleBias = new Vector4(1.0f, 0.0f, 0.0f, 0.0f);
937+
}
938+
}
939+
925940
static void DoUberPostProcess(in UberPostParameters parameters,
926941
RTHandle source,
927942
RTHandle destination,
@@ -956,6 +971,8 @@ static void DoUberPostProcess(in UberPostParameters parameters,
956971
cmd.SetComputeVectorParam(parameters.uberPostCS, HDShaderIDs._BloomDirtScaleOffset, parameters.bloomDirtTileOffset);
957972
cmd.SetComputeVectorParam(parameters.uberPostCS, HDShaderIDs._BloomThreshold, parameters.bloomThreshold);
958973

974+
// Alpha scale and bias (only used when alpha is enabled)
975+
cmd.SetComputeVectorParam(parameters.uberPostCS, HDShaderIDs._AlphaScaleBias, parameters.alphaScaleBias);
959976

960977
// Dispatch uber post
961978
cmd.SetComputeVectorParam(parameters.uberPostCS, "_DebugFlags", new Vector4(parameters.outputColorLog ? 1 : 0, 0, 0, 0));

com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/UberPost.compute

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ CBUFFER_START(cb0)
4444
float4 _BloomDirtScaleOffset;
4545
float4 _BloomBicubicParams;
4646
float4 _DebugFlags;
47+
float4 _AlphaScaleBias;
4748
CBUFFER_END
4849

4950
#define DistCenter _DistortionParams1.xy
@@ -77,6 +78,9 @@ CBUFFER_END
7778

7879
#define OutputLogEnabled _DebugFlags.x
7980

81+
#define AlphaScale _AlphaScaleBias.x
82+
#define AlphaBias _AlphaScaleBias.y
83+
8084
float2 DistortUV(float2 uv)
8185
{
8286
// Lens distortion
@@ -218,8 +222,10 @@ void Uber(uint3 dispatchThreadId : SV_DispatchThreadID)
218222
// Alpha mask
219223
#ifdef ENABLE_ALPHA
220224
// Post processing is not applied on pixels with zero alpha
225+
// The alpha scale and bias control how steep is the transition between the post-processed and plain regions
226+
float alpha = inputColor.a * AlphaScale + AlphaBias;
221227
// Saturate is necessary to avoid issues when additive blending pushes the alpha over 1.
222-
color.xyz = lerp(inputColor.xyz, color.xyz, saturate(inputColor.a));
228+
color.xyz = lerp(inputColor.xyz, color.xyz, saturate(alpha));
223229
#endif
224230

225231
// Done

com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -714,6 +714,8 @@ static class HDShaderIDs
714714
public static readonly int _ChromaSpectralLut = Shader.PropertyToID("_ChromaSpectralLut");
715715
public static readonly int _ChromaParams = Shader.PropertyToID("_ChromaParams");
716716

717+
public static readonly int _AlphaScaleBias = Shader.PropertyToID("_AlphaScaleBias");
718+
717719
public static readonly int _VignetteParams1 = Shader.PropertyToID("_VignetteParams1");
718720
public static readonly int _VignetteParams2 = Shader.PropertyToID("_VignetteParams2");
719721
public static readonly int _VignetteColor = Shader.PropertyToID("_VignetteColor");

0 commit comments

Comments
 (0)