扫描Resource目录里面可能未使用的prefab,输出一个可能无效的资源列表

可能未使用的prefab满足以下规则:

1、不被其他prefab和场景直接引用—-遍历GUID校验排除

2、不被其他prefab和场景间接引用,prefab脚本里面传入其他预设的名称或者路径—-遍历prefab名称排除

3、不被代码里面直接引用—-遍历CS文件校验prefab名称排除

为什么说是可能未使用的prefab,因为还有一种情况:

4、不被代码间接引用,如预设Anniver_01,在代码中是”Anniver_“+number,这种暂时没有好办法解决。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112

static public void checkByGUIDPrefab(Dictionary<string, PrefabData> guidPrefabDic, List<string> allResPathList)
{
//校验GUID
int nIndex = 0;
for (nIndex = 0; nIndex != allResPathList.Count; ++nIndex)
{
if (EditorUtility.DisplayCancelableProgressBar("正在扫描预设与场景中--校验GUID引用", "收集中..." + nIndex, (nIndex*1.0f)/ allResPathList.Count))
{
EditorUtility.ClearProgressBar();
return;
}
checkReference(guidPrefabDic, allResPathList[nIndex], true);
}

//校验预设里面包含其他预设的名称
for (nIndex = 0; nIndex != allResPathList.Count; ++nIndex)
{
if (EditorUtility.DisplayCancelableProgressBar("正在扫描预设与场景中--校验预设名引用", "收集中..." + nIndex, (nIndex * 1.0f) / allResPathList.Count))
{
EditorUtility.ClearProgressBar();
return;
}
checkNameReference(guidPrefabDic, allResPathList[nIndex]);
}

//除了预设和场景引用 还有代码引用
List<string> resPathList = new List<string>();
string[] codePath = Directory.GetFiles("Assets", "*.cs", SearchOption.AllDirectories);
foreach (string fi in codePath)
{
resPathList.Add(fi);
}

//校验代码引用
for (nIndex = 0; nIndex != resPathList.Count; ++nIndex)
{
if (EditorUtility.DisplayCancelableProgressBar("正在扫描CS源码中--校验预设名引用", "收集中..." + nIndex, (nIndex * 1.0f) / resPathList.Count))
{
EditorUtility.ClearProgressBar();
return;
}
checkReference(guidPrefabDic, resPathList[nIndex], false);
}
//还有一些主要是为了Alpha通道分离 将一张图片转换成了预设
//判断在OriginRes中是否有同名的.png文件存在 如果存在则淘汰掉

string filePath = "Assets/_OriginRes/";
string[] fis = Directory.GetFiles(filePath, "*.png", SearchOption.AllDirectories);

//写文件吧::::
List<string> unUsePrefabList = new List<string>();
foreach (string key in guidPrefabDic.Keys)
{
if (!guidPrefabDic[key].isReference && !isExistSameNamePngFile(fis, guidPrefabDic[key].fileName))
{
//Assets/Resources/_NewPanel/BillRecordPanel/BillRecordPanel.prefab 路径转文件名
//codeSrcPrefab.Add(AssetDatabase.GUIDToAssetPath(key), 1);
//Debug.LogError("找到未使用的预设名字:" + guidPrefabDic[key].fileName);
unUsePrefabList.Add(guidPrefabDic[key].fileName);
unUsePrefabPathList.Add(AssetDatabase.GUIDToAssetPath(key));
}
}
EditorUtility.DisplayCancelableProgressBar("扫描结束", "写入本地文件...", 1f);

File.WriteAllLines("Assets/possible_unused_prefab.txt", unUsePrefabPathList.ToArray());
EditorUtility.ClearProgressBar();

//for (int i = 0; i < unUsePrefabPathList.Count; i++)
//{
// System.IO.File.Copy(unUsePrefabPathList[i], @"Assets/Resources/Test1/" + Path.GetFileNameWithoutExtension(unUsePrefabPathList[i]), true);
//}
//拷贝文件至指定目录 试试看

}
/// <summary>
/// 校验GUID或者名称
/// </summary>
/// <param name="guidPrefabDic"></param>
/// <param name="resFilePath"></param>
/// <param name="checkGUID"></param>
static public void checkReference(Dictionary<string, PrefabData> guidPrefabDic, string resFilePath, bool checkGUID = true)
{
FileStream fs = new FileStream(resFilePath, FileMode.Open, FileAccess.Read);
byte[] buff = new byte[fs.Length];
fs.Read(buff, 0, (int)fs.Length);
string strText = Encoding.Default.GetString(buff);
fs.Close();

foreach (string key in guidPrefabDic.Keys)
{
if (guidPrefabDic[key].isReference == true)
{
continue;
}
int nStar = 0;
string checkStr = "";
if (checkGUID)
{
checkStr = key;
}
else
{
checkStr = guidPrefabDic[key].fileName;
}
nStar = strText.IndexOf(checkStr);
if (nStar != -1)
{
guidPrefabDic[key].isReference = true;
}
}
}

Read more »

一.插件简介

FX Maker是Unity3d一款非常流行的效果制作插件。不但有超过300种效果预制体, 还可以自己制作效果。包含Mesh Effect 和Particle Effect。

优点:资源库大,可以将消耗资源非常多的粒子效果转换为帧动画效果。当然也可以直接用不转帧动画的效果,这种效果是画面最好的,但是对显卡开销大。帧动画显卡开销小,占内存大,适合移动平台。Fx Maker还能自动保存。

二.使用步骤

1.导入包

选择菜单【Assets】/【Import Package】/【Custom Package…】,导入FXMaker插件

在这里插入图片描述

导入成功后,在Project面板中可见FXMaker资源文件

在这里插入图片描述

2.打开主场景sceneFXMaker

Read more »

框架

主要涉及到三个概念:GameRoot,GameState,GameSystem

GameRoot

游戏的主入口,游戏场景在GameRoot.scene场景下,场景上有个”_GameRoot”的节点,上面就挂了这个脚本,如下图所示:

在这里插入图片描述

GameRoot是游戏的入口,管理游戏里所有的GameSystem,负责GameState的切换等等。State的切换见下面这个函数:

在这里插入图片描述

GameState

(下面提到的状态或者State都是GameState的意思)

游戏的流程主要以State的切换来组织,直观表现为不同界面的切换。这是一个抽象的东西,虽然直观上当前的界面,但是对它的抽象不仅仅局限于界面。

Read more »

Unity3D会根据文件的后缀名将文件转换为特定的类型对象存储起来,后期获取时根据这些类型取出打包的数据,记录不同后缀文件打包后的类型:

后缀:prefab->GameObject,加载后需要调用Instantiate函数实例化才能使用

后缀:txt、xml、bytes-> TextAsset,数据保存在TextAsset的bytes属性中

后缀:bmp、jpg、png -> Texture2D

问题描述:

1000张的jpg图片拖入Unity,格式设为Texture,并且进行不压缩的方式打包成AssetBundle格式。原本一共才50M的jpg,最后居然打包出来340M的AssetBundle!!!翻了快7倍!!!

jpg是一种有损压缩方式,在打包的过程中,Unity3D会将jpg图片打包成Texture2D,格式转换和解码的过程中增加文件的大小,进而会导致安装包体积变大。

解决方案:利用Unity的打包机制,将jpg图片后缀改为.bytes,打包成TextAsset,减小包的体积,但加载时增加了一步计算量。

在这里插入图片描述

Read more »

虽然网上有很多关于Lua热更新的资料,但是有些内容对于很多初学者来说有些晦涩难懂,为此,下面就通过几个具体的例子给大家介绍下Lua热更新原理及用法。

热更新原理
Lua的 require(modelname) 把一个lua文件加载存放到package.loaded[modelname]。当我们加载一个模块的时候,会先判断是否在package.loaded中已存在,若存在则返回改模块,不存在才会加载(loadfile),防止重复加载。package.loaded是一个Table,其中包含了全局表_G、默认加载的模块(string, debug, package, io, os, table, math, coroutine)和用户加载的模块。

Lua热更新
最简单粗暴的热更新就是将package.loaded[modelname]的值置为nil,强制重新加载:

在这里插入图片描述

这样做虽然能完成热更,但问题是已经引用了该模块的地方不会得到更新, 因此我们需要将引用该模块的地方的值也做对应的更新。

在这里插入图片描述

示例
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

Read more »

管道机制实现了对全部步骤的流式化封装和管理(streaming workflows with pipelines)。

管道机制更像是编程技巧的创新,而非算法的创新。

利用pipeline我们可以方便的减少代码量同时让机器学习的流程变得直观

在这里插入图片描述

需要做如下操作,容易看出,训练测试集重复了代码

1
2
3
4
5
6
7
8
9
10
vect = CountVectorizer()
tfidf = TfidfTransformer()
clf = SGDClassifier()
vX = vect.fit_transform(Xtrain)
tfidfX = tfidf.fit_transform(vX)
predicted = clf.fit_predict(tfidfX)
# Now evaluate all steps on test set
vX = vect.fit_transform(Xtest)
tfidfX = tfidf.fit_transform(vX)
predicted = clf.fit_predict(tfidfX)

利用pipeline,上面代码可以抽象为:

1
2
3
4
5
6
7
8
pipeline = Pipeline([
('vect', CountVectorizer()),
('tfidf', TfidfTransformer()),
('clf', SGDClassifier()),
])
predicted = pipeline.fit(Xtrain).predict(Xtrain)
# Now evaluate all steps on test set
predicted = pipeline.predict(Xtest)
Read more »

Sequential模型

Sequential是由一系列层构成的,每层之间都只有一个输入和输出张量tensor,典型的线型模型结构。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers

# Define Sequential model with 3 layers
model = keras.Sequential(
[
layers.Dense(2, activation="relu", name="layer1"),
layers.Dense(3, activation="relu", name="layer2"),
layers.Dense(4, name="layer3"),
]
)
# Call model on a test input
x = tf.ones((3, 3))
y = model(x)

等价于

1
2
3
4
5
6
7
8
# Create 3 layers
layer1 = layers.Dense(2, activation="relu", name="layer1")
layer2 = layers.Dense(3, activation="relu", name="layer2")
layer3 = layers.Dense(4, name="layer3")

# Call layers on a test input
x = tf.ones((3, 3))
y = layer3(layer2(layer1(x)))

模型动态添加层

1
2
3
4
model = keras.Sequential()
model.add(layers.Dense(2, activation="relu"))
model.add(layers.Dense(3, activation="relu"))
model.add(layers.Dense(4))

指定输入层数据大小:keras.Input

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from tensorflow import keras
from tensorflow.keras import layers

model = keras.Sequential()
model.add(keras.Input(shape=(4,)))
model.add(layers.Dense(2, activation="relu"))

model.summary()

# Model: "sequential"
# _________________________________________________________________
# Layer (type) Output Shape Param #
# =================================================================
# dense (Dense) (None, 2) 10
# =================================================================
# Total params: 10
# Trainable params: 10
# Non-trainable params: 0
# _________________________________________________________________

调试显示model参数

Read more »

执行模式

1、Eager Execution:TensorFlow 2.0默认开启。类似于 python 这样的命令式编程,写好程序之后,不需要编译,就可以直接运行了,而且非常直观。

1
2
3
4
5
6
7
8
import tensorflow as tf

print(tf.executing_eagerly())
# True
v1 = [[2.]]
m = tf.matmul(v1, v1)
print("v1*v1, {}".format(m))
# v1*v1, [[4.]]

2、Graph Execution:预先定义计算图,运行时反复使用,不能改变.适合大规模部署,适合嵌入式平台.Session 用来给定 Graph 的输入,指定 Graph 中的结果获取方式, 并启动数据在 Graph 中的流动.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import tensorflow.compat.v1 as tf

tf.disable_eager_execution()

# 1、定义了一个简单的“计算图”
a = tf.constant(1)
b = tf.constant(1)
# 等价于 c = tf.add(a, b),c是张量a和张量b通过 tf.add 这一操作(Operation)所形成的新张量
c = a + b

# 2、# 实例化一个会话(Session)
# 通过会话的 run() 方法对计算图里的节点(张量)进行实际的计算
sess = tf.Session()
c_ = sess.run(c)
print(c_)
# 2

启用 Eager Execution 会改变 TensorFlow 运算的行为方式 - 现在它们会立即评估并将值返回给 Python. 由于无需构建计算图并稍后在会话中运行,可以轻松使用 print() 或调试程序检查结果。评估、输出和检查张量值不会中断计算梯度的流程。

即使没有训练,也可以在 Eager Execution 中调用模型并检查输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import tensorflow as tf

(mnist_images, mnist_labels), _ = tf.keras.datasets.mnist.load_data()

dataset = tf.data.Dataset.from_tensor_slices(
(tf.cast(mnist_images[..., tf.newaxis] / 255, tf.float32),
tf.cast(mnist_labels, tf.int64)))
dataset = dataset.shuffle(1000).batch(32)

# for x, y in dataset:
# print(x)
# print(y)

mnist_model = tf.keras.Sequential([
tf.keras.layers.Conv2D(16, [3, 3], activation='relu',
input_shape=(None, None, 1)),
tf.keras.layers.Conv2D(16, [3, 3], activation='relu'),
tf.keras.layers.GlobalAveragePooling2D(),
tf.keras.layers.Dense(10)
])

# 即使没有训练,也可以在 Eager Execution 中调用模型并检查输出:
for images, labels in dataset.take(1):
print("Logits: ", mnist_model(images[0:1]).numpy())

张量与变量

Tensor张量是具有统一类型(称为 dtype)的多维数组。张量与 np.arrays 有一定的相似性,所有张量都是不可变的,永远无法更新张量的内容,只能创建新的张量。

Read more »

1.引言
    图像在捕获、传输、处理等过程中会由于噪声的影响而使画质失真,消除噪声是图像预处理的一项重要任务。目前已有许多种图像滤波技术,典型的方法是根据邻域内像素的加权平均值对像素的值进行调整。由于彩色图像每个像素点的值是一个彩色向量,故在彩色图像处理中,基于向量处理的滤波方法是一类有效、可行的重要方法,如将一个移动窗口中的向量排序后其末尾向量作为输出的有序向量法;利用两个彩色向量间的角度作为排序基准的向量方向滤波器;对向量的方向和幅值分别进行处理后再合并的混合方向滤波器;以及输入输出关系用有理函数进行表示的向量有理滤波器。对于受噪声污染的像素,这些滤波器能够较好的检出并进行有效处理,但却不能很好地保持未受噪声破坏的像素的特性。另一方面,模糊技术已广泛应用于图像处理领域。

在图像滤波方面,Lee等提出了一种加权模糊均值滤波器,即任意像素的值由其所在窗口内像素的加权均值所代替,权重由存放在知识库中的隶属度值确定,知识库由专家给出或通过参考图像的直方图确定,这种方法能够有效剔除脉冲噪声。Choi等设计了三种不同功能的滤波器,作为规则后件相应于不同情况(规则前件)下的输出口。而Law等则利用高斯滤波器对图像进行平滑,高斯滤波器的参数由模糊推理确定。此外,当一个像素点与邻域像素的属性值差异较大时,则该像素点或是边缘点,或是噪声点,Vail de Ville等利用模糊逻辑对此进行处理,通过迭代滤波的方法消除噪声,并利用滤波后的方差自适应地调整隶属度函数的参数。

    
对于一个性能好的滤波器,要求既要有效抑制噪声,又要保持边缘和细节信息的完整性。然而在一些常规的滤波方法中,一些好的细节信息往往被误认为噪声而进行处理,导致图像的细节信息受到破坏。这种问题就属于噪声和好的细节信息间的模糊性或不确定性问题,而模糊逻辑是处理不确定性问题的一种有效方法。为此,可以采用一种基于模糊逻辑的彩色图像滤波方法,利用一个像素与邻域像素的接近程度作为其属于该局部区域的程度,以此对图像进行模糊化.模糊化后图像的隶属度值可用于判断一个像素点是噪声点还是好的细节点,不同情况下模糊规则有不同的输出,对模糊推理获得的隶属度进行反变换可以获得滤波后的图像。对彩色图像,三个分量分别以同样的方法进行处理即可。

2.图像滤波算法分类
目前常用的图像滤波算法很多,大体上可分为基于图像域的滤波算法和基于变换域的滤波算法。前者是直接在图像空间中进行的处理,而后者是闷接地在图像的变换域中进行的处理。空域滤波是在图像空间借助模板进行邻域操作完成的,根据特点一般可以分为线性滤波和非线性滤波两大类。线性滤波就是用滤波窗口中各象素灰度值的线性变换来代替被处理象素的灰度值,其滤波窗口大小为:

经过线性平滑滤波,相当于图像经过了一个二维的低通滤波器,虽然是降低了噪声,但同时也模糊了图像的边缘和细节,这是这类滤波算法存在的通病。非线性滤波算法克服了线性滤波算法的不足,可以有效地消除一些孤立的噪声点并且具有很好的图像细节信息保护能力。非线性滤波算法的种类繁多,很难对它进行概括性的数学描述。从数学角度看,非线性滤波是采用微分、积分、多项式运算、坐标变换等方法对图像进行某种形式的处理,具有方法直观、制作简便等优点:但当要处理较大的数字图像数据时,由于图像阵列很大,如果没有发现比较高效的算法,计算上会变得很烦琐,存在着滤波的广度和构成方式的模糊,计算时问长,预测性差等缺点,这样就会降低其在现实工作中的使用价值。

同样情况下如果采用图像变换的方法,如傅里叶算法、沃尔什算法等间接处理技术,就可以获得更为有效的处理方法。所谓的图像频谱变换则是将图像从空间域线性傅里叶变换到频谱域,监测和研究图像的频谱特性,并且进行滤波处理,最终将处理后的频谱经过傅里叶逆变换恢复图像到空间域。虽然,非线性滤波算法对线性滤波算法的缺点进行了一定的改善,然而,仍然很难在抑制噪声和保护细节信息这一对固有的矛盾之问得到较好的折衷。

3.基于模糊理论的图像滤波方法
    自从1965年美国加里福尼亚大学控制论专家L A.Zadeh教授提出模糊数学以来,模期技术被广泛地应用于番个领域。近几年柬,模糊技术已经成功地应用于非线性滤波领域,提出了很多针对图像滤波的模糊算法。基于模糊推理的图像滤波算法允许人们将模糊规则与传统的精确算法相结合,因而具有运算简单、设计灵活、鲁棒性强等特点。并且能够在抑制噪声和保护细节信息这一对固有的矛盾之间得到较好的折衷。正因为模糊滤波算法拥有这些优点,所以得到学者们越来越多的关注,发展的速度也越来越快。
  
Dimitri Van De Ville在IEEE TRANSACTIONS ON FUZZY SYSTEMS发布了一篇名为Noise Reduction by Fuzzy Image Filtering的图像模糊滤波去噪论文,取得了较好的处理效果,论文主要工作包括:计算中心像素点的8个方向的模糊导数;根据模糊导数的值来加权8邻域的像素值得到偏置 ;将得到的 与中心像素点的值相加。

  
 

Read more »

在图像去雾这个领域,几乎没有人不知道《Single Image Haze Removal Using Dark Channel Prior》这篇文章,该文是2009年CVPR最佳论文。作者何凯明博士,2007年清华大学毕业,2011年香港中文大学博士毕业,可谓是功力深厚,感叹于国内一些所谓博士的水平,何这样的博士才可以真正叫做Doctor。

关于何博士的一些资料和论文,大家可以访问这里:http://research.microsoft.com/en-us/um/people/kahe/
开始接触何的这篇论文是在2011年,说实在的那个时候,只是随便浏览了下,看到里面的soft matting过程比较复杂,并且执行速度非常慢,就没有什么大的兴趣。最近又偶尔拾起,仔细研读,觉得论文的推理步骤特别清晰,讲解很到位。恰好适逢浏览到其另外一篇文章《Guided Image Filtering》 ,其中提到了可以用导向滤波来代替soft matting的过程,且速度很快,因此,我对去雾的兴趣算法又大大提高了。  

本文主要上是对《Single Image Haze Removal Using Dark Channel Prior》的翻译、整理、及部分解释。如果您的英文水平好,建议看原文可能来的更爽些。

 大气散射模型:描述了雾化图像的退化过程 :

I(x):观测到的图像(含有雾的图像)
J(x): 景物的实际图像(不含雾的图像)
t(x):  透射率
A  :全球大气光成分
去雾的目标就是从I(x)中复原J(x) 、A、 t(x)
A虽然是未知量,但一般情况下,在8位深度图像中,它是一个三通道强度值均接近于255的全局常量,唯一的未知来那个就是散射率t(x),在求得t(x)的情况下,可以很容易将每一个像素点恢复成清晰的J(x),因此关键问题在于t(x)的求解。

暗原色先验算法:
   
   算法是通过对户外无雾图像的观察得出的:在绝大多数非天空的局部区域里,某些像素总会至少有一个颜色通道具有很低的值。
   公式描述为: 对于一副图像J定义:

Read more »