Unity引擎材质球残留贴图引用的处理
大家好,我是阿赵。
这次来分享一下Unity引擎材质球残留贴图引用的处理
一、 问题
在使用Unity调整美术效果的时候,我们很经常会有这样的操作,比如:
1、 同一个材质球切换不同的Shader、
比如我现在有2个Shader,其中第一个Shader的参数是这样的:
Properties{_MainTex ("MainTex", 2D) = "white" {}_MaskTex("MaskTex",2D) = "black" {}_floatVal("FloatVal",float) = 1_rangeVal("RangeVal",Range(0,1)) = 1_vecVal ("VectorVal",Vector) = (1,1,1,1)_colVal ("ColorVal",Color) = (1,1,1,1)}
而第二个Shader的参数是这样的:
Properties{_MainTex ("MainTex", 2D) = "white" {}_specTex("SpecTex",2D) = "black" {}_floatVal("FloatVal",float) = 1_rangeVal("RangeVal",Range(0,1)) = 1_vecVal ("VectorVal",Vector) = (1,1,1,1)_colVal ("ColorVal",Color) = (1,1,1,1)}
可以看出,它们两个的参数几乎一样,区别只是在一张贴图的名称不同。
假如先在材质球里选第一个Shader,并且把两个贴图的赋上,现在材质球是这样:

然后在这个材质球里面,把Shader改成第二个Shader,会变成这样:

很明显,第二张贴图由于名字不一样,所以这个Shader上不会显示之前的那张贴图。
这时候疑问来了,换了Shader之后,之前的贴图通道里面的引用,是不是就不用管了呢?

这时候,可以打开Debug来看这个材质球的参数:

可以看到,刚才使用在上一个Shader里面的贴图_MaskTex,其实还是保存在引用里面的。这说明一个问题,假如我们给一个材质球替换Shader,其实上一个Shader使用而当前Shader没有使用的字段参数,都保存在材质球的引用里面。如果我们继续使用这个材质球,那么打包资源的时候很可能就会带着一张我们根本没有用到的贴图。
2、 同一个Shader修改参数的名称
还是拿第一个Shader作为例子:
Properties{_MainTex ("MainTex", 2D) = "white" {}_MaskTex("MaskTex",2D) = "black" {}_floatVal("FloatVal",float) = 1_rangeVal("RangeVal",Range(0,1)) = 1_vecVal ("VectorVal",Vector) = (1,1,1,1)_colVal ("ColorVal",Color) = (1,1,1,1)}

还是把上面的2张贴图都赋上。
  这时候,假如我修改一下其中一张贴图的变量名
Properties{_MainTex ("MainTex", 2D) = "white" {}_MaskTex2("MaskTex",2D) = "black" {}_floatVal("FloatVal",float) = 1_rangeVal("RangeVal",Range(0,1)) = 1_vecVal ("VectorVal",Vector) = (1,1,1,1)_colVal ("ColorVal",Color) = (1,1,1,1)}
我把_MaskTex改成了_MaskTex2。

这个时候,会发现之前赋予的_MaskTex贴图消失不见了。
这时候问题又来了。是不是修改了Shader里面的变量声明,那么之前声明的变量引用的贴图就消失了呢?
同样的打开Debug模式看:

虽然新增了_MaskTex2的保存项,但实际上原来的_MaskTex贴图还是存在的,引用的贴图也依然存在。所以同样的道理,如果这个时候我们继续使用这个材质球,那么打包的时候,就会包含了一张我们已经不用了的贴图。
通过上面2个例子可以说明,其实材质球上面已经保存过的参数,不论材质球当前的Shader是否有声明变量,都会在Saved Properties里面一直存在着。但如果不用Debug模式去观察,可能很多使用Unity的朋友都不知道这个问题的存在。这可以说是Unity引擎设计上的一个缺陷。一般使用Unity进行美术资源编辑的,都是美工同事们,他们一般都不会去使用Debug模式,而正常模式下的材质球属性显示里面又没有任何的提示,所以虽然包含了多余的美术资源,但他们是很难发现的。
二、 解决问题。
如果我们通过材质球的Reset选项去清空材质球的所有参数

当然是可以把不用的贴图给清理掉。但那样做的话,会顺便把其他我们正常使用的属性也清理掉了。这显然不是我们想要达到的目的。
我们的目的很简单,就是保留现在的Shader用到的参数,去掉已经不需要的参数。Unity似乎没有直接提供这样的手段,起码阿赵我没有找到。不过我们可以通过另外一种迂回一点的手段,去实现这个目的。
思路是这样的:
1、 获得材质球当前使用的Shader的所有属性名称
通过
ShaderUtil.GetPropertyCount(shader);
可以获得当前Shader声明的变量个数
2、 使用当前Shader创建一个新的临时材质球
Material newMat = new Material(shader);
3、 通过遍历所有属性名称,从旧的材质球上面获取对应的变量参数,然后赋予给新的临时材质球。
由于不同的变量需要用不同的方法获取和赋值,所以需要知道每一个变量的类型,通过
ShaderUtil.ShaderPropertyType propType = ShaderUtil.GetPropertyType(shader,i);
可以获得变量类型

类型只有5种,所以根据类型分别去操作就行了。Range和Float其实是一样的,用GetFloat和SetFloat方法获取就行。
4、 通过复制材质球属性,把临时材质球的所有属性赋予给原来的材质球。
通过方法:
mat.CopyPropertiesFromMaterial(newMat);
可以把临时材质球的所有属性复制给原来的材质球。
5、 最后保存一下原来的材质球
通过这些手段之后,目的达到了,不使用的变量被清空,需要的变量保留下来。

通过这个思路,可以写一个批处理的工具,批量清理材质球。
三、 源码
根据自己的情况,写一个UnityEditor的工具,然后遍历需要的材质球,传入方法:
private void CleanUnusedProp(Material mat)
{if(mat == null){return;}//获得当前材质球使用的ShaderShader shader = mat.shader;//创建一个临时的材质球Material newMat = new Material(shader);//获得Shader声明的变量的数量int propCount = ShaderUtil.GetPropertyCount(shader);for(int i = 0;i<propCount;i++){//获得变量的类型ShaderUtil.ShaderPropertyType propType = ShaderUtil.GetPropertyType(shader,i);//获得变量的名称string propName = ShaderUtil.GetPropertyName(shader, i);//根据变量类型赋值switch(propType){case ShaderUtil.ShaderPropertyType.Float:newMat.SetFloat(propName, mat.GetFloat(propName));break;case ShaderUtil.ShaderPropertyType.Range:newMat.SetFloat(propName, mat.GetFloat(propName));break;case ShaderUtil.ShaderPropertyType.Vector:newMat.SetVector(propName, mat.GetVector(propName));break;case ShaderUtil.ShaderPropertyType.Color:newMat.SetColor(propName, mat.GetColor(propName));break;case ShaderUtil.ShaderPropertyType.TexEnv:newMat.SetTexture(propName, mat.GetTexture(propName));break; }}//复制材质球参数mat.CopyPropertiesFromMaterial(newMat);//保存材质球EditorUtility.SetDirty(mat);AssetDatabase.SaveAssets();AssetDatabase.Refresh();
}
相关文章:
Unity引擎材质球残留贴图引用的处理
大家好,我是阿赵。 这次来分享一下Unity引擎材质球残留贴图引用的处理 一、 问题 在使用Unity调整美术效果的时候,我们很经常会有这样的操作,比如: 1、 同一个材质球切换不同的Shader、 比如我现在有2个Shader,…...
Flutter鸿蒙next中封装一个列表组件
1. 创建Flutter项目 首先,确保你已经安装了Flutter SDK,并创建一个新的Flutter项目: flutter create podcast_app cd podcast_app2. 封装列表组件 我们将在lib目录下创建一个新的文件,命名为podcast_list.dart,用于…...
层次与网络的视觉对话:树图与力引导布局的双剑合璧
目录 目的内容树图绘制目的步骤参考代码结果与分析 力引导布局算法目的参考代码结果与分析 总结 目的 掌握常用可视化软件与工具:学习和熟练使用常用的数据可视化软件和工具,如Matplotlib、Seaborn、Plotly、Tableau等。这些工具提供了用于创建图表、图…...
python将数据集中所有文件名升序制作txt文件(医学影像)
import os import re # 设定图像文件所在的路径 img_path ./2d/images/ #需修改路径 # 获取该路径下的所有文件名 img_list os.listdir(img_path) # 过滤出以.nii结尾的文件名 nii_list [f for f in img_list if f.endswith(.nii)] # 使用正则表达式从文件名中提…...
【The Art of Unit Testing 3_自学笔记06】3.4 + 3.5 单元测试核心技能之:函数式注入与模块化注入的解决方案简介
文章目录 3.4 函数式依赖注入技术 Functional injection techniques3.5 模块化依赖注入技术 Modular injection techniques 写在前面 上一篇的最后部分对第三章后续内容做了一个概括性的梳理,并给出了断开依赖项的最简单的实现方案,函数参数值注入法。本…...
【VSCode】配置
安装插件 C vscode-icons gdb调试 https://www.bilibili.com/video/BV15U4y1x7b2/?spm_id_from333.999.0.0&vd_sourcedf0ce73d9b9b61e6d4771898f1441f7f https://www.bilibili.com/video/BV1pU4y1W74Z?spm_id_from333.788.recommend_more_video.-1&vd_sourcedf0…...
Linux 常用命令整理大全及命令使用心得
本文章是为了总结自己用过的命令,以及一些心得,网上有很多类似的,但自己总结才能更好的理解。 文章目录 一、文件和目录管理01、 ls :列出目录内容02、cd:更改当前目录03、pwd:显示当前工作目录04、mkdir&a…...
计算器的实现
计算器的⼀般实现 计算器的一般实现:优化:使⽤函数指针数组的实现: 计算器的一般实现: #include <stdio.h> int add(int a, int b) {return a b; } int sub(int a, int b) {return a - b; } int mul(int a, int b) {retur…...
这个工具帮你快速实现数据集成和同步
在这个信息爆炸的时代,数据的流动和同步逐渐成为企业运营的命脉。然而,企业正面临着前所未有的数据挑战,无论是跨地域的分公司协作,还是云服务与本地数据库的交互,数据的集成、清洗、转换和加载(ETL&#x…...
论文阅读:Computational Long Exposure Mobile Photography (一)
这篇文章是谷歌发表在 2023 ACM transaction on Graphic 上的一篇文章,介绍如何在手机摄影中实现长曝光的一些拍摄效果。 Abstract 长曝光摄影能拍出令人惊叹的影像,用运动模糊来呈现场景中的移动元素。它通常有两种模式,分别产生前景模糊或…...
项目解决方案:多地连锁药店高清视频监控系统建设解决方案(设计方案)
目录 一.项目背景 1.1背景描述 1.2需求分析 二.设计依据和建设目标 2.1设计依据 2.2建设目标 三.系统设计实现 3.1系统方案设计 3.2网络组网说明 四.建设系统特色 4.1安全性 4.2节约建设成本 4.3原有资源的再利用 4.4可扩展性 五.产品介绍 5.1概述 5.2设备…...
utf-8、pbkdf2_sha
#utf-8加密、解密 import base64 base64.b64encode(lienlien123.encode(utf-8)) bbGllbmxpZW4xMjM base64.b64decode(bbGllbmxpZW4xMjM.decode(utf-8)) blienlien123 #pbkdf2_sha加密,校验 # 该种密码在不同时刻会有产生不同的加密结果 # 该加密方法使用的是散列…...
Java之包,抽象类,接口
目录 包 导入包 静态导入 将类放入包 常见的系统包 抽象类 语法规则 注意事项: 抽象类的作用 接口 实现多个接口 接口间的继承 接口使用实例 (法一)实现Comparable接口的compareTo()方法 (法二)实现Comp…...
HarmonyOS鸿蒙开发入门,常用ArkUI组件学习(二)
书接上回,让我们继续来学习ArkUI的其他组件 目录,可以点击跳转到想要了解的组件详细内容 组件四:Button组件五:Slider组件六: Column & Row组件七:循环控制组件八: List 组件四:…...
斩!JavaScript语法进阶
一、DOM 概述 DOM 是 JavaScript 操作网页的接口,全称为“文档对象模型”(Document Object Model)。当网页被加载时,浏览器将网页转为一个DOM,并用JS进行各种操作。比如:改变页面中的HTML 元素及其属性&am…...
UFO:Windows操作系统的具象智能代理
近年来,随着AI技术的发展,智能代理在各种应用中扮演着越来越重要的角色。微软推出的UFO(User-Focused Operator)正是这样一个出色的多代理框架,旨在通过无缝导航和操作,满足用户在Windows操作系统中跨多个应…...
win10/11无休眠设置和断电后电池模式自动休眠而不是睡眠-用以省电
1、打开休眠设置选项 打开控制面板\所有控制面板项\电源选项\ 左侧的选择电源按钮的功能 默认状态没有休眠 1、管理员权限打开cmd或者power shell 2、输入一下指令,打开休眠选项 powercfg -hibernate on关闭后重新打开 控制面板\所有控制面板项\电源选项\左侧的选…...
【动态规划之斐波那契数列模型】——累加递推型动态规划
文章目录 第N个泰波那契数列面试题08.01.三步问题使用最小花费爬楼梯解码问题 第N个泰波那契数列 解题思路: 泰波那契数列的第 N 项定义为前面三项之和,即 T0 0, T1 1, T2 1,从 T3 开始,每一项都等于前三项的和。要找到第 N 项…...
5g通信系统用到的crc码
5g通信系统用到的crc码 关注 在5G通信系统中,CRC码(循环冗余校验码)扮演着关键角色,它通过执行多项式除法运算来检测数据在传输过程中是否发生错误。5G通信系统中采用了多种CRC码,每种码都有其独特的计算方法和校验特…...
Ubuntu-22.04 虚拟机安装
1. Ubuntu安装方式 1.1. 基于物理介质安装 光盘安装:通过将 Ubuntu 镜像刻录到光盘,在计算机 BIOS/UEFI 中设置光盘为第一启动项,然后按照安装程序的提示进行语言选择、分区、用户信息设置等操作来完成安装。这种方式需要有光盘刻录设备和空…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...
django filter 统计数量 按属性去重
在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...
转转集团旗下首家二手多品类循环仓店“超级转转”开业
6月9日,国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解,“超级…...
Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)
在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马(服务器方面的)的原理,连接,以及各种木马及连接工具的分享 文件木马:https://w…...
【Linux】Linux 系统默认的目录及作用说明
博主介绍:✌全网粉丝23W,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...
如何应对敏捷转型中的团队阻力
应对敏捷转型中的团队阻力需要明确沟通敏捷转型目的、提升团队参与感、提供充分的培训与支持、逐步推进敏捷实践、建立清晰的奖励和反馈机制。其中,明确沟通敏捷转型目的尤为关键,团队成员只有清晰理解转型背后的原因和利益,才能降低对变化的…...
Qt 事件处理中 return 的深入解析
Qt 事件处理中 return 的深入解析 在 Qt 事件处理中,return 语句的使用是另一个关键概念,它与 event->accept()/event->ignore() 密切相关但作用不同。让我们详细分析一下它们之间的关系和工作原理。 核心区别:不同层级的事件处理 方…...
如何配置一个sql server使得其它用户可以通过excel odbc获取数据
要让其他用户通过 Excel 使用 ODBC 连接到 SQL Server 获取数据,你需要完成以下配置步骤: ✅ 一、在 SQL Server 端配置(服务器设置) 1. 启用 TCP/IP 协议 打开 “SQL Server 配置管理器”。导航到:SQL Server 网络配…...
OCR MLLM Evaluation
为什么需要评测体系?——背景与矛盾 能干的事: 看清楚发票、身份证上的字(准确率>90%),速度飞快(眨眼间完成)。干不了的事: 碰到复杂表格(合并单元…...
解析“道作为序位生成器”的核心原理
解析“道作为序位生成器”的核心原理 以下完整展开道函数的零点调控机制,重点解析"道作为序位生成器"的核心原理与实现框架: 一、道函数的零点调控机制 1. 道作为序位生成器 道在认知坐标系$(x_{\text{物}}, y_{\text{意}}, z_{\text{文}}…...
