Unity Mask原理及自定义遮罩
主要内容
- StencilBuffer是什么?
- 自定义Shader来实现遮罩
- Unity Mask的原理
1.什么是StencilBuffer
GPU在渲染前会为每个像素点分配一个1字节(8位)大小的内存区域,即StencilBuffer。
在决定是否要渲染某个像素点之前,会将它当前的StencilBuffer的值与某个参考值(stencilID)进行指定的逻辑运算(Stencil Comparison),如果运算结果为True,则渲染这个像素点,否则就不渲染。
如下图所示,默认分配的StencilBuffer为0,我们将绿色范围内的StencilBuffer设为1,渲染前,把当前像素点的StencilBuffer与参考值1进行是否相等的逻辑运算,如果相等,则渲染。那么,最后屏幕上只有绿色区域的内容才会被渲染出来。
2.自定义shader来实现遮罩
了解了上面StencilBuffer的原理,我们来看一看Unity的Shader是如何巧妙地利用StencilBuffer来实现遮罩的。
首先我们来抽象一下Unity在渲染一个2D场景时的整个过程:
- GPU先为整个屏幕的所有像素点创建StencilBuffer,默认为0。
- 按场景中节点父子顺序,依次从上向下选择要渲染的节点
- 渲染某个节点时,取出当前节点区域中每个像素点的StencilBuffer值,然后和参考值(stencilID)做比较(Stencil Comparison),如果为True,则渲染,并根据操作规则(Stencil Operation)修改当前像素点的StencilBuffer值;否则不渲染,也不操作当前像素点的StencilBuffer值;
- 继续选择下一个需要渲染的节点。
所有需要渲染的节点依次地取出StencilBuffer,进行比较,比较完成后进行修改,然后继续渲染下一个节点。
2.1 Unity Shader 中对Stencil字段定义
Unity自带的shader中,你经常会看到如下的字段供你修改:
我们知道在渲染每个节点时,都经历了取值-比较-修改的过程。上面的字段就是在这个三个过程中用到的参数。
在取当前像素点的StencilBuffer值时,会与Stencil Read Mask进行与(&)运算,比如本来的StencilBuffer是9(0000 1001),当Stencil Read Mask为8(0000 1000)时,取出来的值就是8(0000 1000)。
取出8后,将8与Stencil ID做对比,对比的方式为Stencil Comparison。Stencil Comparison是一个枚举类型,定义如下:
| 值 | 枚举类型 | 含义 |
|---|---|---|
| 0 | Disabled | 不进行比较 |
| 1 | Never | 永远为False |
| 2 | Less | StencilBuffer小于Stencil ID时为True |
| 3 | Equal | StencilBuffer等于Stencil ID时为True |
| 4 | LessEqual | StencilBuffer小于等于Stencil ID时为True |
| 5 | Greater | StencilBuffer小于Stencil ID时为True |
| 6 | NotEqual | StencilBuffer不等于Stencil ID时为True |
| 7 | GraterEqual | StencilBuffer大于等于Stencil ID时为True |
| 8 | Always | 永远为True |
比较结果为True时,渲染这个像素点,并进行Stencil Operation操作,Stencil Operation是一个枚举类型,定义如下:
| 值 | 枚举类型 | 含义 |
|---|---|---|
| 0 | Keep | 保持当前的StencilBuffer值 |
| 1 | Zero | 将StencilBuffer置为0 |
| 2 | Replace | 用Stencil ID的值替换StencilBuffer |
| 3 | IncreamentStaturate | StencilBuffer+=1, 超过255置为255 |
| 4 | DecrementStaturate | StencilBuffer-=1,小于0置为0 |
| 5 | Invert | StencilBuffer取反 |
| 6 | IncrementWrap | StencilBuffer+=1, 超过255置为0 |
| 7 | DecrementWrap | StencilBuffer-=1,小于0置为255 |
在写入最终的StencilBuffer值之前,先和Stencil Write Mask进行与(&)操作,将&之后的结果写入。
Color Mask是渲染时的RGBA四个通道的四位掩码,本文不做详细阐述。
2.2 自定义Shader实现裁剪
了解了Shader对Stencil的定义后,我们可以通过自定义Shader,来实现一个简单的裁剪。如下图,我们想让一个长条状的绿色图片只在白色区域内渲染,超出白色区域的部分不渲染。
场景的层级关系如下:
white_bg材质的shader参数如图:
green_img材质的shader参数如图:
这样就实现了裁剪的效果,整个渲染过程过程是这样的:
- 整个屏幕上的所有像素点的StencilBuffer值置为0
- 渲染白色底板时,取出白色底板区域内的每个像素点的StencilBuffer值,由于Stencil Comparison用的8,永远为True,所以白色底板的所有像素点都会被渲染。而且由于Stencil Operation为2,所以会用Stencil ID即120替换StencilBuffer值的值,这样白色底板区域内的所有像素点的StencilBuffer值都变成了120
- 渲染绿色长条时,取出绿色区域内所有像素点的StencilBuffer值,由于Stencil Comparison用的3,即将StencilBuffer值于Stencil ID120作比较,相等时为True,这样绿色长条中只有位于白色区域内的像素点才回被渲染出来。另外它的Stencil Operation为0,即不改变StencilBuffer值。
3.Unity Mask原理
当你知道了如何利用Shader的Stencil字段来实现自定义的遮罩,你就很容易明白Mask的原理了。
在你添加一个Mask组件时,它便会自动在裁剪层创建一个Stencil Comparison为8,Stencil Operation为2的Shader材质,并根据情况初始化一个Stencil ID。然后为它所有的子层级创建一个Stencil Comparison为3,Stencil ID与其相同的Shader材质来实现裁剪效果。
如果有兴趣深入了解的话,可以看一下Mask的源码,核心函数:
public virtual Material GetModifiedMaterial(Material baseMaterial)
链接:https://juejin.cn/post/6844904038408912909
Unity Mask原理及自定义遮罩的更多相关文章
- JAVA之旅(二十五)——文件复制,字符流的缓冲区,BufferedWriter,BufferedReader,通过缓冲区复制文件,readLine工作原理,自定义readLine
JAVA之旅(二十五)--文件复制,字符流的缓冲区,BufferedWriter,BufferedReader,通过缓冲区复制文件,readLine工作原理,自定义readLine 我们继续IO上个篇 ...
- 【Unity】7.6 自定义输入
分类:Unity.C#.VS2015 创建日期:2016-04-21 一.简介 在Unity中可以创建自定义的虚拟按键,然后将设备的输入映射到自定义的按键上.使用虚拟按键的好处是可以让游戏玩家自己定义 ...
- Spring MVC内容协商实现原理及自定义配置【享学Spring MVC】
每篇一句 在绝对力量面前,一切技巧都是浮云 前言 上文 介绍了Http内容协商的一些概念,以及Spring MVC内置的4种协商方式使用介绍.本文主要针对Spring MVC内容协商方式:从步骤.原理 ...
- 【SpringBoot1.x】SpringBoot1.x 启动配置原理 和 自定义starter
SpringBoot1.x 启动配置原理 和 自定义starter 启动配置原理 本节源码 启动过程主要为: new SpringApplication(sources) 创建 SpringAppli ...
- WPF打印原理,自定义打印
一.基础知识 1.System.Printing命名空间 我们可以先看一下System.Printing命名空间,东西其实很多,功能也非常强大,可以说能够控制打印的每一个细节,曾经对PrintDial ...
- Android自定义遮罩层设计
在做网页设计时,前端设计人员会经常用到基于JS开发的遮罩层,并且背景半透明.这样的效果怎么样在Android上实现呢?这个实现并不困难,先来上效果图: <ignore_js_op> 201 ...
- 深入了解View实现原理以及自定义View详解
下面几篇文章对View的原理讲的非常详细. Android LayoutInflater原理分析,带你一步步深入了解View(一) Android视图绘制流程完全解析,带你一步步深入了解View(二) ...
- (转)浅谈dedecms模板引擎工作原理及自定义标签
理解织梦模板引擎有什么意义?一方面可以更好地自定义标签.更多在于了解织梦系统,理解模板引擎是理解织梦工作原理的第一步.理解织梦会使我们写php代码时更顺手,同时能学习一些php代码的组织方式. 这似乎 ...
- 贝塞尔曲线:原理、自定义贝塞尔曲线View、使用!!!
一.原理 转自:http://www.2cto.com/kf/201401/275838.html Android动画学习Demo(3) 沿着贝塞尔曲线移动的Property Animation Pr ...
- SpringBoot之旅第六篇-启动原理及自定义starter
一.引言 SpringBoot的一大优势就是Starter,由于SpringBoot有很多开箱即用的Starter依赖,使得我们开发变得简单,我们不需要过多的关注框架的配置. 在日常开发中,我们也会自 ...
随机推荐
- C#/.NET/.NET Core技术前沿周刊 | 第 21 期(2025年1.6-1.12)
前言 C#/.NET/.NET Core技术前沿周刊,你的每周技术指南针!记录.追踪C#/.NET/.NET Core领域.生态的每周最新.最实用.最有价值的技术文章.社区动态.优质项目和学习资源等. ...
- 云辅助隐私集合求交(Server-Aided PSI)协议介绍:学习
原文来自:云辅助隐私集合求交(Server-Aided PSI)协议介绍,下面学习一波,并记录一些笔记. 背景 总结: 1.PSI-CA和PSI相比,前者在乎的是交集的大小,后者在乎的是交集本身.另外 ...
- C++:typedef 与 #define 的区别
1.执行上不同 关键字 typedef 在编译阶段有效,由于是在编译阶段,因此 typedef 有类型检查的功能. #define 则是宏定义,发生在预处理阶段,也就是编译之前,它只进行简单而机械的字 ...
- C# Dev GridView当前行
DEV获取GridControl当前行 //直接通过gridView获取当前行 dr=this.gridView1.GetDataRow(this.gridView1.FocusedRowHandle ...
- 使用 SOUI 开发高 DPI 桌面应用程序[转载]
原文:使用 SOUI 开发高 DPI 桌面应用程序_吹泡泡的小猫的博客-CSDN博客 补充说明:soui3以后版本对dpi的支持更完善了,用起来也更简单了. 1 应用程序感知 DPI 变化 在 Win ...
- CSP 初赛要点复习
位运算 逻辑与.按位与之类的东西是不同的!"逻辑"的是判断两个数都不为 \(0\),"按位"的是判断两个数的每一个二进制位与的结果,是不同的.其他运算也类似. ...
- 深度学习中CUDA环境安装教程
首先说明,本人是小白,一次安装,可能有不对的地方,望包含. 安装CUDA 因为我们是深度学习,很多时候要用到gpu进行训练,所以我们需要一种方式加快训练速度. 通俗地说,CUDA是一种协助" ...
- 批量视频剪辑软件开心版合集——CRVideoMate、固乔剪辑助手、批量剪辑大师MV批量创作大师、ai全自动剪辑
CRVideoMate(推荐) 非常好用的批量剪辑工具,如果是简单的基础处理完全是够用了. 软件的官网:http://www.cr-soft.net/crvideomate.html 如果经济允许推荐 ...
- FastAPI 请求体参数与 Pydantic 模型完全指南:从基础到嵌套模型实战 🚀
title: FastAPI 请求体参数与 Pydantic 模型完全指南:从基础到嵌套模型实战 date: 2025/3/7 updated: 2025/3/7 author: cmdragon e ...
- ppt 文字 +图 样式 设计
1. 设计前 设计后 图 +文字排版 图多 字少