本文介绍一种快捷清理Unity材质球上关联的废弃贴图引用的方法,全程无痛方便,推荐大家在自己项目中做一次全局清理。

材质球的无用贴图残留是这样产生的:

第一步,创建一个带有多张贴图材质球资源

第二步,直接切换成一个使用更少贴图数量的shader,看上去这个材质球似乎清理了多余的贴图引用,但是实际上它这个机制隐藏了资源引用

第三步,选择材质球资源,点击Select Dependencies,显示所有依赖,果然原有的两张贴图资源还被引用着

  由上面的重现步骤来看,我们日常的美术制作流程是非常容易引入上述的冗余问题的,材质球shader的切换,并不会清理掉多余贴图槽位上的资源引用,导致资源被冗余包含到发布包中,白白浪费内存,浪费加载带宽。

  所以我们就非常有必要对项目中的所有材质文件做一次全局大扫除,达到优化资源的目的。我们仅仅需要一个简单的批处理脚本,该脚本会清理掉材质球上所有没有被shader引用到的贴图资源引用。

下面给出核心代码,使用了一个小技巧来保证材质资源引用正确,希望对大家有用
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System;
using UnityEngine;
using UnityEditor;static class MaterialCleaner {public static bool ClearMaterialAsset( Material m ) {if ( m == null ) {return false;}var path = AssetDatabase.GetAssetPath( m );if ( String.IsNullOrEmpty( path ) ) {return false;}var deps = AssetDatabase.GetDependencies( new String[] { path } );var deps_textures = deps.Where( s => IsTextureAsset( s ) ).ToList();var used_textures = new HashSet<String>();var shader = m.shader;var newMat = new Material( shader );var c = ShaderUtil.GetPropertyCount( shader );for ( int i = 0; i < c; ++i ) {var type = ShaderUtil.GetPropertyType( shader, i );var name = ShaderUtil.GetPropertyName( shader, i );var value = m.GetProperty( i );switch ( type ) {case ShaderUtil.ShaderPropertyType.Color: {newMat.SetColor( name, m.GetColor( name ) );}break;case ShaderUtil.ShaderPropertyType.Float: {newMat.SetFloat( name, m.GetFloat( name ) );}break;case ShaderUtil.ShaderPropertyType.Range: {newMat.SetFloat( name, ( float )value );}break;case ShaderUtil.ShaderPropertyType.TexEnv: {newMat.SetTexture( name, ( Texture )value );newMat.SetTextureOffset( name, m.GetTextureOffset( name ) );newMat.SetTextureScale( name, m.GetTextureScale( name ) );var tpath = AssetDatabase.GetAssetPath( ( Texture )value );if ( !String.IsNullOrEmpty( tpath ) ) {used_textures.Add( tpath );}}break;case ShaderUtil.ShaderPropertyType.Vector: {newMat.SetVector( name, ( Vector4 )value );}break;}}bool rebuild = false;if ( used_textures.Count != deps_textures.Count ) {for ( int i = 0; i < deps_textures.Count; ++i ) {var _fn = deps_textures[ i ];if ( !used_textures.Contains( _fn ) ) {rebuild = true;UnityEngine.Debug.LogWarning( String.Format( "unused texture: {0}", _fn ) );}}}if ( !rebuild ) {if ( newMat != null ) {UnityEngine.Object.DestroyImmediate( newMat );}return false;}String basePath;String fn;String ext;SplitFullFilename( path, out fn, out ext, out basePath );var tempAssetPath = String.Format( "{0}{1}_temp.{2}", basePath, fn, ext );var _test = AssetDatabase.LoadAllAssetsAtPath( tempAssetPath );if ( _test != null ) {AssetDatabase.DeleteAsset( tempAssetPath );}// create a new material to replace it latterAssetDatabase.CreateAsset( newMat, tempAssetPath );Resources.UnloadAsset( newMat );var tempAssetDataPath = String.Format( "{0}{1}_datatemp.bytes", basePath, fn, ext );if ( File.Exists( tempAssetPath ) ) {// rename it to .bytesFile.Copy( tempAssetPath, tempAssetDataPath, true );// delete temp materialAssetDatabase.DeleteAsset( tempAssetPath );if ( File.Exists( tempAssetDataPath ) ) {// delete original materialFile.Delete( path );// replace original material with .bytes fileFile.Copy( tempAssetDataPath, path, true );// remove bytes fileFile.Delete( tempAssetDataPath );AssetDatabase.Refresh();// make sure the temp file has been removed correctlyif ( File.Exists( tempAssetDataPath ) ) {UnityEngine.Debug.Log( String.Format( "AssetDatabase.DeleteAsset failed: {0}", tempAssetDataPath ) );File.Delete( tempAssetDataPath );AssetDatabase.Refresh();return true;}}}return false;}static void SplitFilename( String qualifiedName, out String outBasename, out String outPath ) {String path = qualifiedName.Replace( '\\', '/' );int i = path.LastIndexOf( '/' );if ( i == -1 ) {outPath = String.Empty;outBasename = qualifiedName;} else {outBasename = path.Substring( i + 1, path.Length - i - 1 );outPath = path.Substring( 0, i + 1 );}}static void SplitBaseFilename( String fullName, out String outBasename, out String outExtention ) {int i = fullName.LastIndexOf( '.' );if ( i == -1 ) {outExtention = String.Empty;outBasename = fullName;} else {outExtention = fullName.Substring( i + 1 );outBasename = fullName.Substring( 0, i );}}static void SplitFullFilename( String qualifiedName, out String outBasename, out String outExtention, out String outPath ) {String fullName = String.Empty;SplitFilename( qualifiedName, out fullName, out outPath );SplitBaseFilename( fullName, out outBasename, out outExtention );}static object GetProperty( this Material material, int index ) {var name = ShaderUtil.GetPropertyName( material.shader, index );var type = ShaderUtil.GetPropertyType( material.shader, index );switch ( type ) {case ShaderUtil.ShaderPropertyType.Color:return material.GetColor( name );case ShaderUtil.ShaderPropertyType.Vector:return material.GetVector( name );case ShaderUtil.ShaderPropertyType.Range:case ShaderUtil.ShaderPropertyType.Float:return material.GetFloat( name );case ShaderUtil.ShaderPropertyType.TexEnv:return material.GetTexture( name );}return null;}static bool IsTextureAsset( String assetPath ) {var ext = Path.GetExtension( assetPath ).ToLower();return ext == ".png" ||ext == ".tga" ||ext == ".jpg" ||ext == ".bmp" ||ext == ".psd" ||ext == ".dds" ||ext == ".exr";}
}

Unity材质清理器相关推荐

  1. Unity开发备忘录000006:用Unity标准着色器构建金属材质效果(二)

    按照Unity开发备忘录000005:用Unity标准着色器构建金属材质效果(一)所介绍的方法,我们又做了一个如下的模型渲染. 在此基础上我们再给它加一个高度贴图,其立体感的细节会更加丰富,如下图: ...

  2. Unity Shader着色器优化

    对游戏开发者而言,着色器长久以来就是游戏开发中的重要部分,在Unity中编写并实现着色器的过程直观且高效,优秀的着色器还可以创造非常精美的游戏画面,同时保证极高的性能.今天将由Unity的技术工程师张 ...

  3. unity材质球发光_Unity Lighting - Emissive Materials 自发光材质(九)

    Whilst Area Lights are not supported by Precomputed Realtime GI, similar soft lighting effects are s ...

  4. Unity材质球个人学习笔记

    Unity材质球个人学习笔记 Shader FX: Lighting and glass effects.( 灯光.玻璃) GUI and UI: For user interface graphic ...

  5. Unity API-----Renderer(渲染器)

    Unity API-----Renderer(渲染器) 官方文档阅读记录 版本 : 2019.3 官方文档传送门 Renderer是UnityEngine命名空间下的一个类. Renderer继承于C ...

  6. UE4材质着色器全面学习教程

    你会学到什么 通过所有着色器类型和设计的实际演示,学习创建材质 要求 对虚幻的基本理解会有所帮助 了解纹理的一般知识(不仅限于UE4)也很有用 描述 在这个系列中,我将带你设置大量不同的材料,教你如何 ...

  7. 学习编写Unity计算着色器 Learn to Write Unity Compute Shaders

    利用图形处理器的力量 你会学到: 如何编写Unity计算着色器 如何在后处理图像过滤器中使用ComputeShaders 如何使用ComputeShaders进行粒子效果和群集 如何使用Structu ...

  8. 系统垃圾文件清理器 制作:China Doll (莫增成)

    @echo off ::修正于2018-10-06 color 4a Title 系统垃圾文件清理器 制作:China Doll (莫增成) echo. echo ================== ...

  9. Unity车轮碰撞器起步刹车太慢

    Unity车轮碰撞器起步刹车太慢 遇到的问题 尝试的办法 刹车慢 起步慢 遇到的问题 在学校学习<物理引擎>专业课的时候,我们的期末作业是用unity的WheelCollider组件来对汽 ...

最新文章

  1. 高德纳咨询公司(Gartner)预测:2019年七大人工智能科技趋势
  2. PHP知识点 自己做个记录
  3. ios 点击出现另外一套tabbar_iOS开发中TabBar再次点击实现刷新效果
  4. deepin执行apt-get update报错https://deb.opera.com/opera-stable stable Release” 没有 Release 文件N: 无法安全地用该
  5. java编译后生成字节码_请问java源文件编译后怎么生成字节码文件?
  6. 基础知识(十三)dlib python人脸检测 特征点定位
  7. 操作系统(13)-操作系统中的死锁及其预防、避免、检测与解除
  8. python中psum是什么意思_python中**是什么
  9. 解决firefox和IE9对icon font字体的跨域访问问题
  10. CentOS下双网卡绑定-bond0
  11. centos7阿里yum源报问题
  12. java 调用百度语音
  13. 【JZOJ4587】Snow的追寻 题解
  14. 宁夏大学计算机科学与技术排名,2016宁夏自治区大学各学科门类最佳专业排行榜...
  15. 论文中文翻译——Vulnerability Dataset Construction Methods Applied To Vulnerability Detection A Survey
  16. Linux应用程序利用libudev库识别USB设备
  17. iOS 应用内购买基础教程 swift篇
  18. 安装webpack及使用
  19. 西电李航 操作系统课程笔记 day11 IO softwarelayer
  20. 一般测试测几轮?每轮测什么?

热门文章

  1. 电源电路中电感为什么会啸叫?
  2. Java开发环境!杭州java开发应届生工资
  3. centos系统删除多余网卡的方法
  4. 阿里云发送短信代码、C++版
  5. java计算机毕业设计慧学IT精品课程网站源码+mysql数据库+系统+lw文档+部署
  6. 【java基础】为什么重写toString()方法?
  7. 【看完这篇就够了!!!通俗易懂】置信度理解(95%的置信度、置信区间)
  8. 请自己写出strcpy函数
  9. python更新织梦网站_织梦DEDECMS自动更新首页的办法
  10. 解决支付宝小程序微信小程序post请求后台接收不到参数的问题