月度归档:2015年09月

拾人牙慧 · 贰

堆沙子

我说这不是解数学题,不是在沙滩上找鹅卵石,更像在沙滩上学习堆沙子。

—— 王小妮在《“孩纸们”》一文中对在肯德基晋升失败后的卢小平同学说的话


什么叫饿

你们哪里知道什么叫饿,你们以为想吃饭的感觉就叫饿?不对。“饿” 是什么?“饿”,是肚子里已经撑得不行了,心里还是饿,还想吃,那才叫 “饿”!

——杜元在《饕餮在六零年》中写道,她的哥哥小林如此教训他的子孙们


谁在统治你

有一个简单的办法可以知道是谁统治着你,那就是看看你不能批评谁。

——美国自由防御倡议(AFDI)的主席帕米拉·盖勒(Pamela Geller)对于在 AFDI 组织的穆罕默德艺术展和漫画比赛上出现的伊斯兰圣战者恐怖袭击时间的回应和生命中提到


土豆和幽默感

她捱到回家,土豆和幽默感都完好无损。

——庄加逊在《女诗人相册》一文中对茨维塔耶娃在受到士兵的冷嘲热讽之后,依然坚强地把领到的土豆用女儿阿利娅的破雪橇拉回了家中。


真正的高贵

优于别人,并不高贵,真正的高贵应该是优于过去的自己

——海明威曾经这样说过


 

拾人牙慧 · 壹

关于同好和同恨

我们爱一个对象的时候,一般不会寻找同好者,甚至会把跟我们爱同一对象的人视为竞争者和侵犯者。但我们恨一个对象时,却总会寻求有志一同的人。

—— 霍弗 《狂热分子》


克鲁伊夫说

我们不会被意大利队击败,但我们会输给他们。

——克鲁伊夫的足球观念颇有哲学意味


戈林关于独裁的证词

不论是民主党、法西斯独裁的、议会制的,还是共产主义专政的国家,人民总是被教导要听从领袖的召唤。领袖所做的,就是告诉人民,他们正遭到攻击,然后谴责和平人士缺乏爱心。

—— 赫尔曼 · 戈林 1946 年 4 月 18 日在纽伦堡审判中的证词


没有无神论者

我是不可知论者,不要叫我什么无神论者。你听过一个不打高尔夫的人自称不打高尔夫球者吗?你见过他们聚集在一起讨论为什么不打高尔夫吗?

——美国天体物理学家兼科普作家尼尔 · 德格拉斯 · 泰森


傻瓜和聪明人

傻瓜不跟聪明人学,聪明人从傻瓜那里学到很多。

—— 瑞士人拉瓦特的名言


Unity3D中如何通过位运算来开启和关闭指定层

在 Unity3D 开发的过程中,我们经常会有选取指定层的需求,例如设定某个摄像机只渲染某几个层的对象,UI 摄像机通常就只选取 UI 所在的层进行渲染,而对于其他层的对象进行忽略;场景摄像机通常会对非 UI 层的所有对象进行渲染,那么除了在 Unity3D Editor 中对场景中已有的 GameObject 直接进行设置之外,我们还有更为灵活的方法吗?当然有了,只要通过简单的位运算就可以把这个需求满足了。

我们先用摄像机来举例吧,Camera 的 cullingMask 属性就是用来设置摄像机渲染层用的,例如我们想设置名为 mainCamera 的摄像机的渲染层为 UI 层和 PopUI 层,那么代码应该如下:

mainCamera.cullingMask = LayerMask.GetMask ("UI", "PopUI");

上面的这段代码非常容易理解,如果我们的需求就是针对有限的少数几个层进行设置的话,这种方法是最好用的。但是,我们通常都会有一些针对特定层进行动态设置的需求,例如我们需要动态地将 PopUI 层从 mainCamera 的 cullingMask 中剔除掉,那么我们应该怎么做呢?可以简单地依照上方的代码来做:

mainCamera.cullingMask = LayerMask.GetMask ("UI");

这样确实能满足我们的需求,但是这是在我们已经完全知道 mainCamera 具体需要渲染哪些层的前提下才可行的。例如我们有一个名为 fightCamera 的摄像机,其对非 UI 和 PopUI 层之外的所有层进行渲染,由于游戏中设计的层数较多,其渲染的层总数可能达到20个,那么此时使用上面的这种方式来关闭某个层那么就显得非常的蛋疼了,我们总不能把那20层的名称都写到代码里头吧,咱们暂且不说可能会写错,这看上去就不是个聪明的办法啊。

这个时候,我们就需要使用到位运算了,例如我们想确保名为 FX 的层在 fightCamera 的 cullingMask 中,那么我们只需要使用下面的代码就可以了:

int layerFXMask = LayerMask.GetMask ("UI");
// 这段代码和上面的代码功能是一样滴
// int layerFXMask = 1 << LayerMask.NameToLayer ("UI");
fightCamera.cullingMask |= layerFXMask;

如果想把 FX 所处的层给关闭了呢,那么使用下面的代码就行了:

int layerFXMask = LayerMask.GetMask ("UI");
// int layerFXMask = 1 << LayerMask.NameToLayer ("UI");
fightCamera.cullingMask &= ~layerFXMask;

如果是想开/关,这样来回切换 FX 所在层的开启状态,那么使用下面的代码就行了:

int layerFXMask = LayerMask.GetMask ("UI");
// int layerFXMask = 1 << LayerMask.NameToLayer ("UI");
fightCamera.cullingMask ^= layerFXMask;

以上这三种情况,分别为开启、关闭和开/关这三种状态,对应的是位运算的按位或、按位与(取反)和按位异或操作。

以上三种情况中最终得到的 cullingMask 值实际上就是一个 int 类型的数字,该方式适用于 Unity3D 中所有接受 LayerMask 作为参数的方法,例如 Physics.Raycast 方法:

public static bool Raycast(Vector3 origin, Vector3 direction, float maxDistance = Mathf.Infinity, int layerMask = DefaultRaycastLayers);

这个方法最后的参数就可以传入我们通过位运算获得的 LayerMask 值,用于指定我们需要进行碰撞检测的层。

如何在Unity3D中优雅的重命名脚本中字段名而不丢失其引用

在进行 Unity3D 开发的过程中,我们难免会碰到想要修改脚本中变量名的情况,可是呢,我们在代码编辑器或者 IDE 中对代码文件中使用到的变量进行 Refactor 之后呢,代码倒是好看了,也是不出错能编译通过了,但是到了实际运行的时候就发现出现各种空引用的问题了。

这是神马鬼啊?估计初学 Unity3D 开发的童鞋还会觉得尼玛简直不知道碰到什么鬼了,熟悉了 Unity3D 开发的童鞋呢,就会会心的一笑,尼玛的 Unity3D 简直不能再坑爹了,好吧,我再重新关联一下变量的引用吧。

这个问题的根源是啥呢?就是我们通常在脚本文件中使用了 Public 的变量,这些变量都会被 Serialized (序列化)保存到对应的 Prefab 文件并持久化到磁盘上,然后每次我们运行游戏的时候呢,Unity3D 会讲这些变量对应的资源引用加载到内存中来,这样我们就可以非常方便地在一个 Prefab 中愉快地使用另一个需要动态显示或者隐藏的 Prefab 或者 GameObject 了。这是我初次进行 Unity3D 开发时候,惊异于 Unity3D 的魔法之一。当然我现在每天都在施展这个魔法啦,不过有的时候呢,总会觉得有些不太爽,因为我有轻微的代码洁癖,只要我觉得这个字段命名的表意不准确,当我发现有更为准确的表意的变量名时,我一定会将变量名或者 Prefab/GameObject 的名称修改过来。修改 Prefab 和 GameObject 的名称倒是完全 OK,Unity3D 会自行帮你把事情做对,但是修改变量名就不一样了,例如在进行改名之后,GameControl.cs 文件中有一个名为 player 的 Public 变量,这个 player 变量指向一个场景中名为 Player 的 GameObject,此时我们的需求发生了改变,这个脚本需要控制两个 Player 了,原本名为 Player 的 GameObject 更名为 PlayerFemale 了,按照正常情况,我们的代码通常也是需要进行修改的,这样变量名和 GameObject 的名称就能保持一致了,方便阅读和理解代码,但是player变量一改名为playerFemale之后,再次运行游戏,就会得到一个空引用异常了,Unity3D 会提示你 playerFemale 变量的引用为空。

叨逼叨了这么多,那么怎么解决呢?尼玛我自己肯定解决不了,这个完全就依赖于 Unity3D 官方的解决方案了。原文链接在这里,大家直接前往围观。

我这里自己也备个忘,做法入下。

如果原先的变量名为 player,修改之后的变量名为 playerFemale,那么我们只需要在使用 Refactor 工具将 player 字段名重命名为 playerFemale,确保所有引用到该变量的代码文件中的 player 字段名称都修改过来了之后。在这个新的变量 playerFemale 上方一行,加入 [FormerlySerializedAs(“player”)] 即可。代码如下:

[FormerlySerializedAs("player")]
public GameObject playerFemale;

如果后续我们还要再将这个 playerFemale 字段名再修改为 playerAssassin 呢,那又肿么办?那就依顺序再加一行 [FormerlySerializedAs(“playerFemale”)] 在原有的 [FormerlySerializedAs(“player”)] 下方即可,代码如下:

[FormerlySerializedAs("player")]
[FormerlySerializedAs("playerFemale")]
public GameObject playerAssassin;

好了,奏是这个样子滴,好棒哒,希望 Unity3D 能变得越来越好用,省得被我们耀华一天到晚问候各种亲戚朋友,是吧。

【撒利学 Shader】之一 UV Mapping 的概念

UV Mapping就是UV贴图的意思,说白了就是将3D中的不规则多面体沿着某条线剪开之后,然后摊开到一个平面上,这样就可以将3D物体上的每个点映射到一张2D的平面贴图上了。

当然这个显然木有我说的这么简单,毕竟3D物体那么不规则,要将一张2D的贴图上的每个像素与3D物体上的各个顶点以及顶点之间映射上也不是件容易的事情,不过显然这个不是我能讨论和想讨论的事情了。我们只需要知道制作UV贴图是3D建模软件一个高级的基础功能就好了,Unity3D拿到这些UV贴图之后直接往模型上贴就好了,不过Unity3D又是如何读取2D贴图中的UV信息,并且能将这个贴图很好地贴到这个模型表面上捏?好吧,其实我也不知道,希望在这个学习Shader的过程中,我们最终能解答这个问题。