SoftMaskForUGUI icon indicating copy to clipboard operation
SoftMaskForUGUI copied to clipboard

Screen Space - Camera, URP, Stacked overlay camera.

Open inertiave opened this issue 3 years ago • 12 comments

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.

image

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 avatar Sep 13 '21 14:09 inertiave

@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.

Metroslim avatar Jul 01 '22 11:07 Metroslim

@inertiave & @Metroslim & @mob-sakai Same issue here. Has anyone found a way to solve this problem?

image

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.

MaxMoussalli avatar Sep 08 '22 12:09 MaxMoussalli

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

MaxMoussalli avatar Sep 08 '22 15:09 MaxMoussalli

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.

MaxMoussalli avatar Sep 09 '22 09:09 MaxMoussalli

Thank you for your reporting! Could you please attach a minimal project (included Assets, Packages and ProjectSettings directories) that reproduces the issue?

repos

mob-sakai avatar Sep 13 '22 07:09 mob-sakai

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

TestSoftMask.zip

https://user-images.githubusercontent.com/36939401/189869238-0b0ae50b-8911-4604-9f52-c2f9079be2a1.mp4

Rekun avatar Sep 13 '22 09:09 Rekun

#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 ///可以试试这个

jackson1991123 avatar Sep 20 '22 16:09 jackson1991123

#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

MaxMoussalli avatar Sep 21 '22 09:09 MaxMoussalli

#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

Rekun avatar Sep 21 '22 10:09 Rekun

yes this is working for camera space but not for overlay anymore

MaxMoussalli avatar Sep 21 '22 10:09 MaxMoussalli

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.^^

Gitburner avatar Nov 18 '22 12:11 Gitburner

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 grafik

Jens-roesing avatar Dec 01 '22 14:12 Jens-roesing