关于 Unity UGUI 中修改 Mask 组件下 Image 等子节点组件的材质无效的问题
前几天同事做了一个效果,希望在原本使用了遮罩组件 Mask 的技能图标(让技能图标变成圆形)上在添加一个置灰的功能,但问题来了:因为是动态根据游戏中玩家的条件才动态置灰,以修改 Mask 下子节点 Image 组件的材质来实现的,但是实际上怎么修改也不起作用,呈现出的效果都只停留在第一次运行时的样子。
一开始我也以为是 shader 的问题,修改的 property 没有生效,但是通过各种测试发现 shader 是已经修改成功的了。就是没有应用上,在查阅了各方资料无效果的情况下只能翻阅 unity 托管在 BitBucket 上的 UI 源码了(赞一个)。
先看看 Mask.cs,通过 StencilBuffer 实现遮罩,继承自 IMaterialModifier,需要实现接口:Material GetModifiedMaterial(Material baseMaterial); 这个接口是用来修改获取的材质来实现遮罩效果。在各种 MonoBehaviour 改变时都会通过 MaskUtilities 这个静态类来向所有的子节点发送 Stencil 状态改变的消息。
所以想知道为什么材质效果总是维持在第一次启动执行时,就看看 Mask.OnEnable 里调用的 MaskUtilities.NotifyStencilStateChanged(this); 做了什么。
public static void NotifyStencilStateChanged(Component mask)
{
var components = ListPool<Component>.Get();
mask.GetComponentsInChildren(components);
for (var i = ; i < components.Count; i++)
{
if (components[i] == null || components[i].gameObject == mask.gameObject)
continue; var toNotify = components[i] as IMaskable;
if (toNotify != null)
toNotify.RecalculateMasking();
}
ListPool<Component>.Release(components);
}
看以上代码可以得知,Mask 会调用所有子节点中继承自 IMaskable 组件(Image 继承 MaskableGraphic, MaskableGraphic 继承自此)的 RecalculateMasking() 函数。该函数将
MaskableGraphic 中的 m_ShouldRecalculateStencil 修改为 true,这样当开始渲染时,每个组件都会被调用 GetModifiedMaterial 以返回一个适用于当前渲染的 材质(有可能会返回一个修改过的拷贝),当 Imange.m_ShouldRecalculateStencil = true 时,会在 GetModifiedMaterial 中返回一个支持 Stencil 的修改过的材质,用于实现 Mask 遮罩效果,所以问题也很明了了,修改 Mask 下的 Image 组件原始的材质是不起作用的,因为实际渲染使用的不是它。
那么如何修改?只需要自己继承一个比如 Image 组件,并重载 GetModifiedMaterial 方法,将基类返回材质保存即可,这就是实际渲染使用的材质,当你想修改置灰时,使用这个材质即可。代码如下:
public class CustomImage : Image
{
public override Material GetModifiedMaterial(Material baseMaterial)
{
Material cModifiedMat = base.GetModifiedMaterial(baseMaterial);
// Do whatever you want with this "cModifiedMat"...
// You can also hold this and process it in your grayscale code.
// ...
return cModifiedMat;
}
}
也可以去看看我在 Unity Answer 上对于该问题的回答:http://answers.unity3d.com/questions/1130203/ui-mask-override-my-shaders-custom-property.html
关于 Unity UGUI 中修改 Mask 组件下 Image 等子节点组件的材质无效的问题的更多相关文章
- C#中怎样在ToolStripMenuItem下再添加子级菜单
场景 在右键菜单ContextMenuStrip下添加子菜单选项可以通过 ContextMenuStrip menuStrip ToolStripMenuItem mnuChartOption = n ...
- 问题:jQuery中遍历XML文件时候,获取子节点children不支持的情况(已解决)
问题描述: 今天在写一个基于 jquery 的读取xml文件的程序时候,需要遍历xml的节点. 代码片段如下: function parse_xml_node(parent,result){ // r ...
- Unity UGUI图文混排(七) -- 下划线
之前更新超链接的时候,忘了搭配实现一个下划线的功能,这篇文章就是来补上这一个功能,时间有点长,一方面没有很好的思路,一方面也没多少时间. 先在网上收集了一下下划线的实现操作,一种是在文本下再创建一个文 ...
- jquery 中选择当前标签下众多相同子标签中的第n个
可以用jquery选择器的:eq选择器或者jquery遍历的eq()方法,下面带那给出ul下第4个li的内容 $("ul li:eq(3)") // 元素的index位置工0开始 ...
- C# 递归程序 获取某个节点下的全部子节点
/// <summary> /// 获取组织结构树 /// </summary> /// <param name="list"></par ...
- Unity优化方向——优化Unity游戏中的图形渲染(译)
CPU bound:CPU性能边界,是指CPU计算时一直处于占用率很高的情况. GPU bound:GPU性能边界,同样的是指GPU计算时一直处于占用率很高的情况. 原文:https://unity3 ...
- Unity UGUI —— 无限循环List
还记得大学毕业刚工作的时候是做flash的开发,那时候看到别人写的各种各样的UI组件就非常佩服,后来自己也慢慢尝试着写,发现其实也就那么回事.UI的开发其实技术的成分相对来说不算多,但是一个好的UI是 ...
- Unity ugui屏幕适配与世界坐标到ugui屏幕坐标的转换
我们知道,如今的移动端设备分辨率五花八门,而开发过程中往往只取一种分辨率作为设计参考,例如采用1920*1080分辨率作为参考分辨率. 选定了一种参考分辨率后,美术设计人员就会固定以这样的分辨率来设计 ...
- Unity UGUI之Button
创建Button后,会出现一个Image组件和一个Button组件,以及Button子节点Text(可以删除不影响功能) 其中Image的Image Type中有四个选项--Simple.Sliced ...
随机推荐
- 【制作镜像】BCEC制作镜像
如要制作的新镜像已存在标准版本镜像,即linux发行版本相同(此处指CentOS6.5 64位),可利用BCEC制作. 在BCEC创建centos6.5系统的可联外网的虚机,ssh到此虚机,用yum方 ...
- 常用数据与VARIANT之间的转换---从网上整理
//头文件 1 #pragma once class VariantConvert { public: VariantConvert(void); ~VariantConvert(void); pub ...
- 正则表达式(.NET)
元字符: \b 单词的开头或结尾,匹配一个位置 . 匹配除换行符以外的任意字符 \d 匹配一位数字 \d{n} n个数字 \d{a,b} a到b个数字,包含a,b \s 匹配任意空白符 ...
- 结合实例分析简单工厂模式&工厂方法模式&抽象工厂模式的区别
之前写过一篇关于工厂模式(Factory Pattern)的随笔,里面分析了简单工厂模式,但对于工厂方法和抽象工厂的分析较为简略.这里重新分析分析三者的区别,工厂模式是java设计模式中比较简单的一个 ...
- Win7下Boost库的安装
Boost库是C++领域公认的经过千锤百炼的知名C++类库,涉及编程中的方方面面,简单记录一下使用时的安装过程 1.boost库的下载 boost库官网主页:www.boost.org 2.安装 将下 ...
- 【转】Vim命令合集以及乱码问题解决
乱码问题 """""""""""""""" ...
- c++与C# winform的消息通讯--(结构体与byte数组的使用)
近期正在做一个蓝牙驱动的使用程序,其中有一块从c++发送数据到C#的部分,网上查了很多资料,大多都是介绍如何通过调用函数获取用户数据.并且在消息发送中,很少介绍如何发送一个结构体,并且结构体里面有 b ...
- Invoke()方法的使用
在多线程编程中,我们经常要在工作线程中去更新界面显示,而在多线程中直接调用界面控件的方法是错误的做法,Invoke 和 BeginInvoke 就是为了解决这个问题而出现的,使你在多线程中安全的更新界 ...
- CentOS 6.4 使用第三方源
1.EPEL源 CentOS 6.x 32-bit (x86/i386):rpm -Uvh http://download.fedoraproject.org/pub/epel/6/i386/ep ...
- windows下的SASS/Compass的安装与卸载
认识SASS/Compass SASS是一种CSS的开发工具,提供了许多便利的写法,大大节省了设计者的时间,使得CSS的开发,变得简单和可维护. SASS与Compass的安装说明 SASS在Wind ...