SoftMaskForUGUI
SoftMaskForUGUI copied to clipboard
Screen Space - Camera, URP, Stacked overlay camera.
I think when the canvas is the screen space camera mode and the camera is stacked overlay camera on URP, it cannot draw a maskable image properly. Just masking the shape in runtime and draw well in scene view.
Is there anything I missed to set up before? the canvas camera for ui is urp overlay camera and added properly to stack camera list. My URP is 12.0.0.
Thanks.
@inertiave & @mob-sakai I've faced the exact same problem in URP while the Camera that display the SoftMask/maskable was in overlay mode. I've managed to saw the mask but it wasn't weel placed and was verticaly fliped.
I guess it's a king of Pipeline/Shader way of stacking the Camera but I didn't managed to customize the shader to make it right.
An easy way to test this bug is to start from the Samples and add a MainCamera as the Base then switch the exisiting Camera to Overlay and Stack it.
@inertiave & @Metroslim & @mob-sakai Same issue here. Has anyone found a way to solve this problem?
What I have noticed is that the mask is aligned badly on the Y axis, on the center of the screen no problem and the more the UI is far from center the more the mask decals.
After some investigation, I found that forcing SOFTMASK_EDITOR in SoftMask.cginc solve the problem for canvas with screen space mode (but cause the problem for overlay mode instead). Sadly it's working only in editor and not in build.
If this can help to find a proper way to fix it...
#ifndef UI_SOFTMASK_INCLUDED
#define UI_SOFTMASK_INCLUDED
sampler2D _SoftMaskTex;
float _Stencil;
float4x4 _GameVP;
float4x4 _GameTVP;
half4 _MaskInteraction;
float CustomStep(float a, float x)
{
return x >= a;
}
fixed Approximately(float4x4 a, float4x4 b)
{
float4x4 d = a - b;
d = float4x4(
abs(d[0]),
abs(d[1]),
abs(d[2]),
abs(d[3])
);
return step(
max(d._m00,max(d._m01,max(d._m02,max(d._m03,
max(d._m10,max(d._m11,max(d._m12,max(d._m13,
max(d._m20,max(d._m21,max(d._m22,max(d._m23,
max(d._m30,max(d._m31,max(d._m32,d._m33))))))))))))))),
0.5);
}
//#if SOFTMASK_EDITOR
float SoftMaskInternal(float4 clipPos, float4 wpos)
//#else
//float SoftMaskInternal(float4 clipPos)
//#endif
{
half2 view = clipPos.xy/_ScreenParams.xy;
//#if SOFTMASK_EDITOR
fixed isSceneView = 1 - Approximately(UNITY_MATRIX_VP, _GameVP);
float4 cpos = mul(_GameTVP, mul(UNITY_MATRIX_M, wpos));
view = lerp(view, cpos.xy / cpos.w * 0.5 + 0.5, isSceneView);
#if UNITY_UV_STARTS_AT_TOP
view.y = lerp(view.y, 1 - view.y, CustomStep(0, _ProjectionParams.x));
#endif
//#elif UNITY_UV_STARTS_AT_TOP
#if UNITY_UV_STARTS_AT_TOP
view.y = lerp(view.y, 1 - view.y, CustomStep(0, _ProjectionParams.x));
#endif
fixed4 mask = tex2D(_SoftMaskTex, view);
half4 alpha = saturate(lerp(fixed4(1, 1, 1, 1), lerp(mask, 1 - mask, _MaskInteraction - 1), _MaskInteraction));
//#if SOFTMASK_EDITOR
alpha *= CustomStep(0, view.x) * CustomStep(view.x, 1) * CustomStep(0, view.y) * CustomStep(view.y, 1);
//#endif
return alpha.x * alpha.y * alpha.z * alpha.w;
}
//#if SOFTMASK_EDITOR
#define SOFTMASK_EDITOR_ONLY(x) x
#define SoftMask(clipPos, worldPosition) SoftMaskInternal(clipPos, worldPosition)
//#else
// #define SOFTMASK_EDITOR_ONLY(x)
// #define SoftMask(clipPos, worldPosition) SoftMaskInternal(clipPos)
//#endif
#endif // UI_SOFTMASK_INCLUDED
So now I fixed it to works in build too but I still having the issues to not working anymore with canvas overlay mode.
#ifndef UI_SOFTMASK_INCLUDED
#define UI_SOFTMASK_INCLUDED
sampler2D _SoftMaskTex;
float _Stencil;
float4x4 _GameVP;
float4x4 _GameTVP;
half4 _MaskInteraction;
float CustomStep(float a, float x)
{
return x >= a;
}
fixed Approximately(float4x4 a, float4x4 b)
{
float4x4 d = a - b;
d = float4x4(
abs(d[0]),
abs(d[1]),
abs(d[2]),
abs(d[3])
);
return step(
max(d._m00,max(d._m01,max(d._m02,max(d._m03,
max(d._m10,max(d._m11,max(d._m12,max(d._m13,
max(d._m20,max(d._m21,max(d._m22,max(d._m23,
max(d._m30,max(d._m31,max(d._m32,d._m33))))))))))))))),
0.5);
}
#if SOFTMASK_EDITOR
float SoftMaskInternal(float4 clipPos, float4 wpos)
#else
float SoftMaskInternal(float4 clipPos)
#endif
{
half2 view = clipPos.xy/_ScreenParams.xy;
#if SOFTMASK_EDITOR
fixed isSceneView = 1 - Approximately(UNITY_MATRIX_VP, _GameVP);
float4 cpos = mul(_GameTVP, mul(UNITY_MATRIX_M, wpos));
view = lerp(view, cpos.xy / cpos.w * 0.5 + 0.5, isSceneView);
/*#if UNITY_UV_STARTS_AT_TOP
view.y = lerp(view.y, 1 - view.y, CustomStep(0, _ProjectionParams.x));
#endif
#elif UNITY_UV_STARTS_AT_TOP
view.y = lerp(view.y, 1 - view.y, CustomStep(0, _ProjectionParams.x));*/
#endif
fixed4 mask = tex2D(_SoftMaskTex, view);
half4 alpha = saturate(lerp(fixed4(1, 1, 1, 1), lerp(mask, 1 - mask, _MaskInteraction - 1), _MaskInteraction));
#if SOFTMASK_EDITOR
alpha *= CustomStep(0, view.x) * CustomStep(view.x, 1) * CustomStep(0, view.y) * CustomStep(view.y, 1);
#endif
return alpha.x * alpha.y * alpha.z * alpha.w;
}
#if SOFTMASK_EDITOR
#define SOFTMASK_EDITOR_ONLY(x) x
#define SoftMask(clipPos, worldPosition) SoftMaskInternal(clipPos, worldPosition)
#else
#define SOFTMASK_EDITOR_ONLY(x)
#define SoftMask(clipPos, worldPosition) SoftMaskInternal(clipPos)
#endif
#endif // UI_SOFTMASK_INCLUDED
So my conclusion is that UNITY_UV_STARTS_AT_TOP is wrong with camera stack. If anyone have an idea on how to fix that, then it should work in all cases.
Thank you for your reporting!
Could you please attach a minimal project (included Assets
, Packages
and ProjectSettings
directories) that reproduces the issue?
I am having the same problem with stack camera, when rotating a mask it doesn't work properly, also, i realized that activating post-process in the stacked camera somehow fixes the issue, but it's not a desired solution. I attach a project and a video
Unity Version 2021.3.0f1
https://user-images.githubusercontent.com/36939401/189869238-0b0ae50b-8911-4604-9f52-c2f9079be2a1.mp4
#ifndef UI_SOFTMASK_INCLUDED #define UI_SOFTMASK_INCLUDED
sampler2D _SoftMaskTex; float _Stencil; float4x4 _GameVP; float4x4 _GameTVP; half4 _MaskInteraction; half4 _MainTex_TexelSize; //this one is filled by unity
float CustomStep(float a, float x) { return x >= a; }
fixed Approximately(float4x4 a, float4x4 b) { float4x4 d = a - b; d = float4x4( abs(d[0]), abs(d[1]), abs(d[2]), abs(d[3]) );
return step(
max(d._m00,max(d._m01,max(d._m02,max(d._m03,
max(d._m10,max(d._m11,max(d._m12,max(d._m13,
max(d._m20,max(d._m21,max(d._m22,max(d._m23,
max(d._m30,max(d._m31,max(d._m32,d._m33))))))))))))))),
0.5);
}
#if SOFTMASK_EDITOR float SoftMaskInternal(float4 clipPos, float4 wpos) #else float SoftMaskInternal(float4 clipPos) #endif { half2 view = clipPos.xy/_ScreenParams.xy; #if SOFTMASK_EDITOR fixed isSceneView = 1 - Approximately(UNITY_MATRIX_VP, _GameVP); float4 cpos = mul(_GameTVP, mul(UNITY_MATRIX_M, wpos)); view = lerp(view, cpos.xy / cpos.w * 0.5 + 0.5, isSceneView); #if UNITY_UV_STARTS_AT_TOP view.y = lerp(view.y, 1 - view.y, CustomStep( _MainTex_TexelSize.y,0)); #endif #elif UNITY_UV_STARTS_AT_TOP ///aim to check DX on device ///CustomStep(_MainTex_TexelSize.y, 0) aim to check if unity has converted the agly uv :< now the uv is view view.y = lerp(view.y, 1 - view.y, CustomStep(_MainTex_TexelSize.y, 0)); #endif
fixed4 mask = tex2D(_SoftMaskTex, view);
half4 alpha = saturate(lerp(fixed4(1, 1, 1, 1), lerp(mask, 1 - mask, _MaskInteraction - 1), _MaskInteraction));
#if SOFTMASK_EDITOR
alpha *= CustomStep(0, view.x) * CustomStep(view.x, 1) * CustomStep(0, view.y) * CustomStep(view.y, 1);
#endif
return alpha.x * alpha.y * alpha.z * alpha.w;
}
#if SOFTMASK_EDITOR #define SOFTMASK_EDITOR_ONLY(x) x #define SoftMask(clipPos, worldPosition) SoftMaskInternal(clipPos, worldPosition) #else #define SOFTMASK_EDITOR_ONLY(x) #define SoftMask(clipPos, worldPosition) SoftMaskInternal(clipPos) #endif
#endif // UI_SOFTMASK_INCLUDED
///this may work, SoftMask.cginc ///可以试试这个
#ifndef UI_SOFTMASK_INCLUDED #define UI_SOFTMASK_INCLUDED
sampler2D _SoftMaskTex; float _Stencil; float4x4 _GameVP; float4x4 _GameTVP; half4 _MaskInteraction; half4 _MainTex_TexelSize; //this one is filled by unity
float CustomStep(float a, float x) { return x >= a; }
fixed Approximately(float4x4 a, float4x4 b) { float4x4 d = a - b; d = float4x4( abs(d[0]), abs(d[1]), abs(d[2]), abs(d[3]) );
return step( max(d._m00,max(d._m01,max(d._m02,max(d._m03, max(d._m10,max(d._m11,max(d._m12,max(d._m13, max(d._m20,max(d._m21,max(d._m22,max(d._m23, max(d._m30,max(d._m31,max(d._m32,d._m33))))))))))))))), 0.5);
}
#if SOFTMASK_EDITOR float SoftMaskInternal(float4 clipPos, float4 wpos) #else float SoftMaskInternal(float4 clipPos) #endif { half2 view = clipPos.xy/_ScreenParams.xy; #if SOFTMASK_EDITOR fixed isSceneView = 1 - Approximately(UNITY_MATRIX_VP, _GameVP); float4 cpos = mul(_GameTVP, mul(UNITY_MATRIX_M, wpos)); view = lerp(view, cpos.xy / cpos.w * 0.5 + 0.5, isSceneView); #if UNITY_UV_STARTS_AT_TOP view.y = lerp(view.y, 1 - view.y, CustomStep( _MainTex_TexelSize.y,0)); #endif #elif UNITY_UV_STARTS_AT_TOP ///aim to check DX on device ///CustomStep(_MainTex_TexelSize.y, 0) aim to check if unity has converted the agly uv :< now the uv is view view.y = lerp(view.y, 1 - view.y, CustomStep(_MainTex_TexelSize.y, 0)); #endif
fixed4 mask = tex2D(_SoftMaskTex, view); half4 alpha = saturate(lerp(fixed4(1, 1, 1, 1), lerp(mask, 1 - mask, _MaskInteraction - 1), _MaskInteraction)); #if SOFTMASK_EDITOR alpha *= CustomStep(0, view.x) * CustomStep(view.x, 1) * CustomStep(0, view.y) * CustomStep(view.y, 1); #endif return alpha.x * alpha.y * alpha.z * alpha.w;
}
#if SOFTMASK_EDITOR #define SOFTMASK_EDITOR_ONLY(x) x #define SoftMask(clipPos, worldPosition) SoftMaskInternal(clipPos, worldPosition) #else #define SOFTMASK_EDITOR_ONLY(x) #define SoftMask(clipPos, worldPosition) SoftMaskInternal(clipPos) #endif
#endif // UI_SOFTMASK_INCLUDED
///this may work, SoftMask.cginc ///可以试试这个
This still not fix for the overlay mode in canvas
#ifndef UI_SOFTMASK_INCLUDED #define UI_SOFTMASK_INCLUDED
sampler2D _SoftMaskTex; float _Stencil; float4x4 _GameVP; float4x4 _GameTVP; half4 _MaskInteraction; half4 _MainTex_TexelSize; //this one is filled by unity
float CustomStep(float a, float x) { return x >= a; }
fixed Approximately(float4x4 a, float4x4 b) { float4x4 d = a - b; d = float4x4( abs(d[0]), abs(d[1]), abs(d[2]), abs(d[3]) );
return step( max(d._m00,max(d._m01,max(d._m02,max(d._m03, max(d._m10,max(d._m11,max(d._m12,max(d._m13, max(d._m20,max(d._m21,max(d._m22,max(d._m23, max(d._m30,max(d._m31,max(d._m32,d._m33))))))))))))))), 0.5);
}
#if SOFTMASK_EDITOR float SoftMaskInternal(float4 clipPos, float4 wpos) #else float SoftMaskInternal(float4 clipPos) #endif { half2 view = clipPos.xy/_ScreenParams.xy; #if SOFTMASK_EDITOR fixed isSceneView = 1 - Approximately(UNITY_MATRIX_VP, _GameVP); float4 cpos = mul(_GameTVP, mul(UNITY_MATRIX_M, wpos)); view = lerp(view, cpos.xy / cpos.w * 0.5 + 0.5, isSceneView); #if UNITY_UV_STARTS_AT_TOP view.y = lerp(view.y, 1 - view.y, CustomStep( _MainTex_TexelSize.y,0)); #endif #elif UNITY_UV_STARTS_AT_TOP ///aim to check DX on device ///CustomStep(_MainTex_TexelSize.y, 0) aim to check if unity has converted the agly uv :< now the uv is view view.y = lerp(view.y, 1 - view.y, CustomStep(_MainTex_TexelSize.y, 0)); #endif
fixed4 mask = tex2D(_SoftMaskTex, view); half4 alpha = saturate(lerp(fixed4(1, 1, 1, 1), lerp(mask, 1 - mask, _MaskInteraction - 1), _MaskInteraction)); #if SOFTMASK_EDITOR alpha *= CustomStep(0, view.x) * CustomStep(view.x, 1) * CustomStep(0, view.y) * CustomStep(view.y, 1); #endif return alpha.x * alpha.y * alpha.z * alpha.w;
}
#if SOFTMASK_EDITOR #define SOFTMASK_EDITOR_ONLY(x) x #define SoftMask(clipPos, worldPosition) SoftMaskInternal(clipPos, worldPosition) #else #define SOFTMASK_EDITOR_ONLY(x) #define SoftMask(clipPos, worldPosition) SoftMaskInternal(clipPos) #endif
#endif // UI_SOFTMASK_INCLUDED
///this may work, SoftMask.cginc ///可以试试这个
this has worked with the bug i had
yes this is working for camera space but not for overlay anymore
Hi. I had the same problem with a overlay camera stack. I have a "Main Camera" (Base, Perspective) and a "UI Camera" (Overlay, Orthographic). It seems to be a scale problem. My fix was to change the Projection>Size of the "UI Camera" to 1. You can also change the Quality>Render Scale to 1 in the Render Pipeline Asset, but it looks bad.^^
Hi. I had the same problem with a overlay camera stack. I have a "Main Camera" (Base, Perspective) and a "UI Camera" (Overlay, Orthographic). It seems to be a scale problem. My fix was to change the Projection>Size of the "UI Camera" to 1. You can also change the Quality>Render Scale to 1 in the Render Pipeline Asset, but it looks bad.^^
I have similar setup like Gitburner, but my error was that i hadn't enabled "post processing" in my UICamera