Unity3D Soft Mask 软遮罩插件

Posted Jaihk662

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity3D Soft Mask 软遮罩插件相关的知识,希望对你有一定的参考价值。

一、如何使用 Soft Mask 插件

下载地址:Soft Mask | GUI Tools | Unity Asset Store

和常用的 Mask 和 RectMask2D 组件一样,SoftMask 也可以用来对 Image、RawImage 等图形单元进行遮罩,仅显示部分区域,不过相对于传统的遮罩,SoftMask 的区域便于更加的平滑,也可以理解为是渐进式遮罩,往往可以通过它来实现一些边缘羽化等效果:

1.1 组件挂载

在需要使用 Soft Mask 遮罩的父节点上,添加 Soft Mask 组件,其中 Source 选择 Texture 或 Sprite,然后选择对应的蒙版图片即可,成功设置后该父节点下的子节点上挂载的对应图形单元会应用遮罩(当然对应图形单元的 shader 需要注入一些额外的逻辑,具体可以参考下一节)

 

1.2 自定义 Shader 实现支持 Soft Mask

若想要 Soft Mask 的表现正确,需要修改现有的 Shader 以支持,需要注意的是:不同 shader 改动可能有所差异,具体可以参阅 Soft Mask - Custom Shader Tutorial v. 1.2 - Google 文档

1. 在 Properties 中添加如下变量

Properties

    …
    _StencilWriteMask        ("Stencil Write Mask", Float) = 255
    _StencilReadMask        ("Stencil Read Mask", Float) = 255
    _ColorMask         ("Color Mask", Float) = 15
    _SoftMask          ("Mask", 2D) = "white" 
 

2. 添加 #pragma 与 #include,其中 #12 和 #18 两行为新添加的内容

SubShader

    …
    Pass
    
        …
        CGPROGRAM
        #pragma target 3.0
        #pragma vertex VertShader
        #pragma fragment PixShader
        …
        #pragma multi_compile __ SOFTMASK_SIMPLE SOFTMASK_SLICED SOFTMASK_TILED

        #include "UnityCG.cginc"
        #include "UnityUI.cginc"
        #include "TMPro_Properties.cginc"
        #include "TMPro.cginc"
        #include "Assets/ThirdParty/SoftMask/Shaders/SoftMask.cginc"
    

3. 添加相关参数并计算

v2f 中加入 SOFTMASK_COORDS(texCoord) ,TEXCOORD 序号顺延即可

struct v2f

    float4 vertex   : SV_POSITION;
    fixed4 color : COLOR;
    float2 texcoord  : TEXCOORD0;
    float4 worldPosition : TEXCOORD1;
    SOFTMASK_COORDS(2)
;

顶点着色器中添加 SOFTMASK_CALCULATE_COORDS(output, pos) 语句

v2f vert(appdata_t IN)

    v2f OUT;
    OUT.worldPosition = IN.vertex;
    OUT.vertex = UnityObjectToClipPos(OUT.worldPosition);

    OUT.texcoord = IN.texcoord;

    #ifdef UNITY_HALF_TEXEL_OFFSET
    OUT.vertex.xy += (_ScreenParams.zw - 1.0) * float2(-1,1) * OUT.vertex.w;
    #endif

    OUT.color = IN.color;
    SOFTMASK_CALCULATE_COORDS(OUT, IN.vertex);
    return OUT;

最后在片段着色器中应用遮罩 SOFTMASK_GET_MASK(input)

fixed4 frag(v2f IN) : SV_Target

    fixed4 color = tex2D(_MainTex, IN.texcoord); 
    color.a *= SOFTMASK_GET_MASK(IN); 
    ...
    color.a = lerp(1, color.a, IN.color.a);
    return color;

需要注意的是:

  • 如果你的 shader 有做 alpha 的预乘,那么 rgb 通道也应乘于如上系数
  • 考虑到更特殊的情况:对于每种不同的混合模式,应用遮罩的算法应当都不相同,具体可以反向推下公式,一个混合的例子是 [_SrcBlend = One, _DstBlend = SrcAlpha],对应的代码就应如下:
color.rgb *= SOFTMASK_GET_MASK(IN);
color.a = 1 - (1 - color.a) * SOFTMASK_GET_MASK(IN);

成功!此时该 Shader 即支持 Soft Mask 了

jQuery遮罩层插件

在网页上常常遇到须要等待非常久的操作,比方导出报表等。为了预防用户点击其它操作或者多次点击同个功能,须要用遮罩层把页面或者操作区盖住。防止用户进行下一步操作。同一时候能够提高界面友好度,让用户知道操作正在运行。

$.fn.extend({
	/**
	 * 给元素加入遮罩层
	 * @param  message  {String}  [可选]遮罩层显示内容
	 */
	mask: function (message) {
		var $target = this,
			fixed = false,
			targetStatic = true;

		if (Object.prototype.toString.call(message) !== ‘[object String]‘ || !message) {
			//假设message为空或者不是字符串,则用默认的消息提示。

message = ‘请稍候。

。。‘; } if ($target.length === 0) { $target = $(‘body‘); } else { if ($target.length > 1) { $target = $target.first(); } if ($target[0] === window || $target[0] === document) { $target = $(‘body‘); } } if($target[0] === document.body){ fixed = true; } //假设目标元素已经有遮罩层,获取遮罩层 var old = $target.data(‘rhui.mask‘); if (old) { old.$content.html(message); center($target, old.$content, fixed); return; } //假设被遮盖的元素是static。把元素改成relative if ($target.css(‘position‘) === ‘static‘) { targetStatic = true; $target.css(‘position‘, ‘relative‘); } var $content, $overlay; if (fixed) { $overlay = $(‘<div class="rhui-mask" style="position:fixed;"></div>‘); $content = $(‘<div class="rhui-mask-content" style="position:fixed;">‘ + message + ‘</div>‘); } else { $overlay = $(‘<div class="rhui-mask"></div>‘); $content = $(‘<div class="rhui-mask-content">‘ + message + ‘</div>‘); } $overlay.appendTo($target); $content.appendTo($target); //显示遮罩层 $overlay.show(); $content.show(); //让遮罩层居中 center($target, $content, fixed); //把遮罩层信息加入到$target $target.data(‘rhui.mask‘, { fixed: fixed, $overlay: $overlay, $content: $content, targetStatic: targetStatic }); /** * 让遮罩层内容居中显示 * @param $target 被遮盖的元素 * @param $content 遮罩层内容元素 * @param fixed 遮罩层是否固定显示 */ function center($target, $content, fixed) { var $window, height = $content.outerHeight(true), width = $content.outerWidth(true); if (fixed) { //假设遮罩层固定显示。让遮罩层在window居中 $window = $(window); $content.css({ left: ($window.width() - width) / 2, top: ($window.height() - height) / 2 }); } else { //让遮罩层在$target中居中 $content.css({ left: ($target.width() - width) / 2, top: ($target.height() - height) / 2 }); } } }, /** * 取消遮罩层 */ unmask: function () { var $target; if (this.length === 0) { $target = $(‘body‘); } else { $target = this.first(); if ($target[0] === window || $target[0] === document) { $target = $(‘body‘); } } var data = $target.data(‘rhui.mask‘); if (!data) { return; } //还原目标元素的position属性 if (data.targetStatic) { $target.css(‘position‘, ‘static‘); } data.$overlay.remove(); data.$content.remove(); $target.removeData(‘rhui.mask‘); } });


插件样式由rhui-mask和rhui-mask-content类控制,rhui-mask是遮罩层样式,rhui-mask-content是遮罩层的提示内容样式。

/* 遮罩层样式 */
.rhui-mask {
	position: absolute;
	top: 0;
	right: 0;
	bottom: 0;
	left: 0;
	z-index: 9000;
	display: block;
	margin: 0;
	padding: 0;
	border-style: none;
	background-color: #777;
	opacity: 0.3;
	zoom: 1;
	filter: alpha(opacity=30);
}

/* 遮罩层显示内容样式 */
.rhui-mask-content {
	position: absolute;
	z-index: 9999;
	display: block;
	margin: 0;
	padding: 15px 20px;
	border: 2px solid rgb(109, 157, 215);
	background-color: #fff;
	color: blue;
	letter-spacing: 2px;
	font-weight: bold;
	font-size: 15px;
	cursor: wait;
}

效果如图所看到的

技术分享

页面调用完整代码

<!DOCTYPE html>
<html>

<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
	<title>网页遮罩层的实现</title>
	<style type="text/css">
		/* 遮罩层样式 */		
		.rhui-mask {
			position: absolute;
			top: 0;
			right: 0;
			bottom: 0;
			left: 0;
			z-index: 9000;
			display: block;
			margin: 0;
			padding: 0;
			border-style: none;
			background-color: #777;
			opacity: 0.3;
			zoom: 1;
			filter: alpha(opacity=30);
		}
		
		/* 遮罩层显示内容样式 */		
		.rhui-mask-content {
			position: absolute;
			z-index: 9999;
			display: block;
			margin: 0;
			padding: 15px 20px;
			border: 2px solid rgb(109, 157, 215);
			background-color: #fff;
			color: blue;
			letter-spacing: 2px;
			font-weight: bold;
			font-size: 15px;
			cursor: wait;
		}
	</style>
	<script type="text/javascript" src="http://cdn.bootcss.com/jquery/1.11.3/jquery.js"></script>
	<script type="text/javascript">
		$.fn.extend({
			/**
			 * 给元素加入遮罩层
			 * @param  message  {String}  [可选]遮罩层显示内容
			 */
			mask: function (message) {
				var $target = this,
					fixed = false,
					targetStatic = true;

				if (Object.prototype.toString.call(message) !== ‘[object String]‘ || !message) {
					//假设message为空或者不是字符串,则用默认的消息提示。
					message = ‘请稍候。

。。‘; } if ($target.length === 0) { $target = $(‘body‘); } else { if ($target.length > 1) { $target = $target.first(); } if ($target[0] === window || $target[0] === document) { $target = $(‘body‘); } } if ($target[0] === document.body) { fixed = true; } //假设目标元素已经有遮罩层,获取遮罩层 var old = $target.data(‘rhui.mask‘); if (old) { old.$content.html(message); center($target, old.$content, fixed); return; } //假设被遮盖的元素是static,把元素改成relative if ($target.css(‘position‘) === ‘static‘) { targetStatic = true; $target.css(‘position‘, ‘relative‘); } var $content, $overlay; if (fixed) { $overlay = $(‘<div class="rhui-mask" style="position:fixed;"></div>‘); $content = $(‘<div class="rhui-mask-content" style="position:fixed;">‘ + message + ‘</div>‘); } else { $overlay = $(‘<div class="rhui-mask"></div>‘); $content = $(‘<div class="rhui-mask-content">‘ + message + ‘</div>‘); } $overlay.appendTo($target); $content.appendTo($target); //显示遮罩层 $overlay.show(); $content.show(); //让遮罩层居中 center($target, $content, fixed); //把遮罩层信息加入到$target $target.data(‘rhui.mask‘, { fixed: fixed, $overlay: $overlay, $content: $content, targetStatic: targetStatic }); /** * 让遮罩层内容居中显示 * @param $target 被遮盖的元素 * @param $content 遮罩层内容元素 * @param fixed 遮罩层是否固定显示 */ function center($target, $content, fixed) { var $window, height = $content.outerHeight(true), width = $content.outerWidth(true); if (fixed) { //假设遮罩层固定显示,让遮罩层在window居中 $window = $(window); $content.css({ left: ($window.width() - width) / 2, top: ($window.height() - height) / 2 }); } else { //让遮罩层在$target中居中 $content.css({ left: ($target.width() - width) / 2, top: ($target.height() - height) / 2 }); } } }, /** * 取消遮罩层 */ unmask: function () { var $target; if (this.length === 0) { $target = $(‘body‘); } else { $target = this.first(); if ($target[0] === window || $target[0] === document) { $target = $(‘body‘); } } var data = $target.data(‘rhui.mask‘); if (!data) { return; } //还原目标元素的position属性 if (data.targetStatic) { $target.css(‘position‘, ‘static‘); } data.$overlay.remove(); data.$content.remove(); $target.removeData(‘rhui.mask‘); } }); </script> </head> <body> <div id="div" style="width:600px;height:300px;margin:10px;border:1px solid red;"></div> <script type="text/javascript"> $(function () { //遮盖整个页面 //仅仅要对window、document和body使用遮罩层。都会遮盖整个页面 //$(window).mask(); //$(window).unmask(); 取消遮罩 //遮盖div $(‘#div‘).mask(‘载入中,请稍候。。

。‘); }); </script> </body> </html>






以上是关于Unity3D Soft Mask 软遮罩插件的主要内容,如果未能解决你的问题,请参考以下文章

Unity3D 2D模式下使用Sprite Mask 注意特点

大神们unity3d里面的圆形遮罩怎么做

Unity3d中UGUI组件精简复盘Mask组件

jQuery遮罩层插件

AE基础(4)-MASK遮罩和形状图层

CSS mask的用法