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();
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1585.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

一行代码实现垂直居中

实现元素垂直居中的方案有很多&#xff0c;比如定位、伸缩盒子、行高等等。 但在 2024 年的Chrome 123 版本中&#xff0c; CSS 原生可以使用 1 个 CSS 属性 align-content: center进行垂直居中。 如何使用 <!DOCTYPE html> <html lang"en"> <head&…

云计算作业一

目录 0. 前置准备 0.1 安装虚拟机 0.2 Linux统一设置 1. Hadoop安装配置 1.1 环境准备 1.2 Hadoop伪分布式安装 1.3 Hadoop集群安装 2. HDFS实验&#xff0c;包括Shell命令操作和Java接口访问 2.1 HDFS操作命令 2.2 通过Java项目访问HDFS 2.3 使用winutils解决警告信…

C# 结构型设计模式----适配器模式

1、简介 简单的说就是将一个类的接口转换成客户希望的另一个接口。 举例理解: 你买了一个苹果手机&#xff0c;但是家里的数据线都是安卓的&#xff0c;你想用安卓的线充你的苹果手机&#xff0c;那你就需要一个转接头。适配器模式就是适用于这种情况。 适配的本质就是转换…

感受野是什么?有什么用?从感受野的角度理解,FCN要堆叠卷积层

参考&#xff1a;感受野 1.感受野是什么 感受野(receptive field)这一概念来自于生物神经科学&#xff0c;是指感觉系统中的任一神经元&#xff0c;其所受到的感受器神经元的支配范围。感受器神经元就是指接收感觉信号的最初级神经元。 而在卷积神经网络中&#xff0c;感受野…

C++基础三(构造函数,形参默认值,函数重载,单例模式,析构函数,内联函数,拷贝构造函数)

C有六个默认函数&#xff0c;分别是&#xff1a; 1、默认构造函数; 2、默认拷贝构造函数; 3、默认析构函数; 4、赋值运算符; 5、取址运算符; 6、取址运算符const; 构造函数 构造函数(初始化类成员变量)&#xff1a; 1、属于类的成员函数之一 …

LEADTOOLS 版本 23 现已发布,引入了 Excel API等众多新功能!

LEADTOOLS 以其在全世界主要国家中占有的市场领导地位&#xff0c;在数码图象开发工具领域中已成为既定的全球领导者&#xff0c;其不断发展和扩展功能&#xff0c;以帮助开发人员构建更好、更强大的应用程序。最新发布的 LEADTOOLS 版本 23引入了许多新功能&#xff0c;包括新…

鸿蒙系统的优势 不足以及兼容性与未来发展前景分析

2024 年 10 月 22 日&#xff1a;华为正式发布原生鸿蒙操作系统 HarmonyOS next&#xff0c;并正式命名为 HarmonyOS 5&#xff0c;这是鸿蒙系统史上最大的升级&#xff0c;实现了国产操作系统从底层架构到应用生态的全面自主可控。 鸿蒙系统与安卓、iOS 相比&#xff0c;具有…

Hive 2.x 的安装与配置

Hive 2.x 的安装与配置 1 简介 基于Hadoop的一个数据仓库工具&#xff0c;可将结构化数据文件映射为一张数据库表&#xff0c;并提供简单[SQL]查询&#xff0c;可将SQL语句转换为MapReduce任务进行运行。 优点 学习成本低&#xff0c;可通过类SQL语句快速实现简单的MapReduce统…

关于图像客观指标的调试总结

1、问题背景 工作中经常有调试图像客观指标的需求&#xff0c;很容易遇到我们自己的环境测试是过的&#xff0c; 但客户那边的环境就是测不过&#xff0c;这时候该怎么办呢&#xff1f; 2、问题分析 首先要改变以往的工作思路&#xff0c;在调试的过程中不能说指标过了就完了&a…

VulkanTutorial(14·descriptor,uniform buffer)

Uniform buffers Descriptor layout and buffer 我们将继续学习3D图形&#xff0c;这需要一个模型-视图-投影矩阵&#xff0c;因此我们要更改向vertex shader传输的数据&#xff0c;也就是通过vertex buffer 但是当实时渲染&#xff0c;每一帧这些数据都有可能变化&#xff0…

Kafka存储机制大揭秘:从日志结构到清理策略的全面解析

文章目录 一、前言二、日志存储结构1.日志文件结构2.topic3.partition4.segment索引文件5.message结构6.message查找过程 三、存储策略1.顺序写2.页缓存3.零拷贝4.缓存机制 四、日志格式演变1.V0 版本2.V1 版本3.V0/V1消息集合4.V2 版本消息格式5.V2版本消息集合 五、偏移量维护…

基于OSS搭建在线教育视频课程分享网站

OSS对象存储服务是海量、安全、低成本、高持久的存储服务。适合于存储大规模非结构化数据&#xff0c;如图片、视频、备份文件和容器/虚拟机镜像等。 安装nginx wget https://nginx.org/download/nginx-1.20.2.tar.gz yum -y install zlib zlib-devel gcc-c pcre-devel open…

HCIA笔记整合

第一部分&#xff1a; OSI七层模型 应用层&#xff1a;人机交互 抽象语言--------编码 表示层&#xff1a;编码------二进制 会话层&#xff1a;提供会话号 传输层&#xff1a;TCP/UDP 分段&#xff08;收到MTU值的限制&#xff09; MTU&#xff1a;最大传输单元&#xff…

如何选择到印尼的海运代理

如何选择到印尼的海运代理 选择合适的海运代理的重要性 海运代理负责安排货物从发货地到目的地的整个运输过程&#xff0c;包括装运、清关、仓储等服务。一个可靠的海运代理能确保货物安全准时到达&#xff0c;并帮助企业节省时间和成本。 选择海运代理需考虑的主要因素 公司…

RK3588的QT交叉编译环境搭建

主要参考为RK3568或RK3288开发板创建交叉编译环境{采用amd64的ubuntu系统配置交叉编译arm64开发环境}(保姆级包括安装QT)超详细记录版_rk3568交叉编译-CSDN博客 先说一下&#xff0c;使用的Ubuntu20.04.5版本&#xff0c;qt源码用的5.14.2版本&#xff0c;交叉编译器使用RK3588…

【Linux】一些Shell脚本编程基础题

目录 一、比较两个数的大小 二、求1-100的素数和 三、编写shell脚本&#xff0c;输入一个数字n并计算1~n的和&#xff0c;同时要求如果输入的数字小于1&#xff0c;则重新输入&#xff0c;直到输入正确的数字为止。 四、编写一个shell脚本用来进行成绩等级评定&#xff0c;…

数据的表现形式(2)

汉字字形码 字形码也叫字模或汉字输出码。字形码是表示汉字字型信息的编码&#xff0c;用来实现计 算机对汉字的输出 如一个16*16点阵的字形码就需要16*16/8个字节的存储空间 二进制的运算 在定点二进制运算中&#xff0c;减法运算一般通过【补码运算的二进制加法器】 进制三要…

Vision - 开源视觉分割算法框架 Grounded SAM2 配置与推理 教程 (1)

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/143388189 免责声明&#xff1a;本文来源于个人知识与公开资料&#xff0c;仅用于学术交流&#xff0c;欢迎讨论&#xff0c;不支持转载。 Ground…

深度学习基础—语言模型和序列生成

引言 深度学习基础—循环神经网络&#xff08;RNN&#xff09;https://blog.csdn.net/sniper_fandc/article/details/143417972?fromshareblogdetail&sharetypeblogdetail&sharerId143417972&sharereferPC&sharesourcesniper_fandc&sharefromfrom_link 上…

leetcode-3-无重复字符的最长子串

题解&#xff1a; 1、初始化一个字典dic_hash{}。 2、初始化左指针i-1&#xff0c;右指针j为s的索引。 #3、初始化变量res1用3 2Q#来 |} 】、 代码&#xff1a;