首页 > 其他分享 >Unity Mask原理及自定义遮罩

Unity Mask原理及自定义遮罩

时间:2024-11-30 15:11:18浏览次数:9  
标签:遮罩 Stencil 自定义 渲染 ID Unity True 像素点 StencilBuffer

主要内容

  1. StencilBuffer是什么?
  2. 自定义Shader来实现遮罩
  3. 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场景时的整个过程:

  1. GPU先为整个屏幕的所有像素点创建StencilBuffer,默认为0。
  2. 按场景中节点父子顺序,依次从上向下选择要渲染的节点
  3. 渲染某个节点时,取出当前节点区域中每个像素点的StencilBuffer值,然后和参考值(stencilID)做比较(Stencil Comparison),如果为True,则渲染,并根据操作规则(Stencil Operation)修改当前像素点的StencilBuffer值;否则不渲染,也不操作当前像素点的StencilBuffer值;
  4. 继续选择下一个需要渲染的节点。

所有需要渲染的节点依次地取出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 ComparisonStencil 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参数如图:

 

这样就实现了裁剪的效果,整个渲染过程过程是这样的:

  1. 整个屏幕上的所有像素点的StencilBuffer值置为0
  2. 渲染白色底板时,取出白色底板区域内的每个像素点的StencilBuffer值,由于Stencil Comparison用的8,永远为True,所以白色底板的所有像素点都会被渲染。而且由于Stencil Operation为2,所以会用Stencil ID即120替换StencilBuffer值的值,这样白色底板区域内的所有像素点的StencilBuffer值都变成了120
  3. 渲染绿色长条时,取出绿色区域内所有像素点的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

标签:遮罩,Stencil,自定义,渲染,ID,Unity,True,像素点,StencilBuffer
From: https://www.cnblogs.com/gangtie/p/18578448

相关文章

  • gofiber: 用go-playground/validator校验参数,自定义错误信息
    一,go-playground/validator官方代码地址https://github.com/go-playground/validator二,安装$goget-ugithub.com/go-playground/validator/v10go:downloadinggithub.com/go-playground/validator/v10v10.23.0go:downloadinggithub.com/gabriel-vasile/mimetypev1.4.......
  • ios短视频开发,自定义缓存策略的实现
    ios短视频开发,自定义缓存策略的实现缓存所占用的空间往往会成为迫使用户卸载应用的最后一根稻草。开发者不能无上限对音视频资源进行缓存,通常的维护手法是通过限制空间大小,比如,用户通常可以接受视频类应用有1G左右的缓存空间,即时通信类应用也许会更大些。因此在ios短视频开发......
  • uni-app vue3 获取 package.json 自定义环境变量
    一、初始化项目 二、添加 package.json 文件(必须)注意:文件里面不要写备注{ "uni-app":{ "scripts":{ "dev":{ "title":"开发版", "env":{ "ENV_TYPE":"dev", "UNI_PLATFORM&q......
  • 【Unity】DrawCall 研究随记
    参考文档:1.BatchBatchBatch.PDF参考文档:2.DrawCall,Batches,SetPasscalls是什么?原理?【匠】DrawCall(绘制调用)是什么DrawCall就是CPU调用图像编程接口,比如DirectX的DrawPrimitive/DrawIndexedPrimitive,OpenGL的glDrawElement/glDrawArrays,以命令GPU进行渲染的操作......
  • vue3自定义指令实现截图
    依赖:•使用html2canvas(需要先安装:npminstallhtml2canvas)。绑定事件:•在目标DOM上绑定click事件。截图逻辑:•点击后调用html2canvas截取目标元素的截图。•使用Canvas的toDataURL()方法生成Base64图片。保存文件:•创建一个a标签,通过downloa......
  • RUOYI参数验证异常处理及自定义注解触发验证抛出异常报错
    目录一.ruoyi与参数验证1.触发报错2.后端现象二.源码分析1.前端代码2.后端代码3.报错分析三.自定义函数注解1.NoNumber注解2.NoNumberMain校验器3.将注解添加进SysRole中4.前端&后端现象一.ruoyi与参数验证1.触发报错对参数验证的使用,从触发参数报错开始,首先对ru......
  • 自定义一个WinForm个性化的TabControl
    系列文章目录第一章自定义一个WinForm异形按钮第二章自定义一个WinForm圆角文本框第三章自定义一个WinForm个性化的TabControl文章目录系列文章目录前言一、效果展示自定义TabControl效果展示二、TabControl自定义1.创建一个MyTabControl2.自定义并暴露出一些常......
  • 客户端WinForm实现Form表单格式自定义
    usingSystem;usingSystem.Collections;usingSystem.Collections.Generic;usingSystem.ComponentModel;usingSystem.ComponentModel.Design;usingSystem.ComponentModel.Design.Serialization;usingSystem.Data;usingSystem.Drawing;usingSystem.Linq;using......
  • 开发者必备:构建自定义CLI格式化工具的完整指南 (5)
    一个工具的命令行界面(CLI)背后其实就是调用相应的API。在这里,我们将实现一个简易的CLI工具,通过它来格式化代码。首先,新建一个名为formattool的项目,并使用pnpminit进行初始化:mkdirformattoolcdformattoolpnpminit-y然后,在项目根目录下创建一个index.js文......
  • Unity中的数学应用 之 插值函数处理角色朝向 (初中难度 +Matlab)
            CodeMonkey教程:https://www.youtube.com/watch?v=QDWlGOocKm8    Siki学院汉化教程:如何使用Unity开发分手厨房(胡闹厨房)-Unity2023-SiKi学院|SiKi学堂-unity|u3d|虚幻|ue4/5|java|python|人工智能|视频教程|在线课程版本:Unity6模板:3D核心(渲......