wordpress 多个子站点,wordpress制作在线云课堂,单位网站建设程序,网站建设员工分工大家好#xff0c;我是阿赵。 这次来分享一下Unity引擎材质球残留贴图引用的处理
一、 问题 在使用Unity调整美术效果的时候#xff0c;我们很经常会有这样的操作#xff0c;比如#xff1a;
1、 同一个材质球切换不同的Shader、
比如我现在有2个Shader#xff0c;… 大家好我是阿赵。 这次来分享一下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张贴图都赋上。
emsp;emsp;这时候假如我修改一下其中一张贴图的变量名
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;ipropCount;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();
}