仅边框立方体
方案一 物理建模
该方案在需要缩放时会表现出劣势:当XYZ缩放不一致时,线框的宽度可能会出现走形。
整体思路:创建仅边框的立方体,并导入Unity,修改碰撞体为Box,调整材质。
模型
- 使用Blender创建基础的立方体,进入编辑模式,全选并Delet,选择“仅删除面”。

- 添加蒙皮修改器

- 在编辑模式下
Ctrl+A调整边框的粗细,直到效果合适。

- 导出为fbx模型并导入Unity。
方案二 手写Shader
该方案在缩放不规则时仍然变现不佳,因立方体六个面默认共用UV。
该问题是可解的:使用带World Space UV的Shader。
整体思路:在 Shader 内部画边框。在计算边框宽度时,除以物体的缩放倍数。
$$\text{Distance} = (\text{物体半尺寸} \times \text{缩放}) - (|\text{对象空间坐标}| \times \text{缩放})$$
以下为Shader Graph的详细步骤:
一、输入属性
材质应包含以下三个可控的输入属性:
Border Width:发光线框的宽度。Emission Color:发光线框的颜色。Base Alpha:基础透明度,控制非线框部分的透明度,默认为0。
二、获得绝对物理坐标
这一步得到的结果是经过缩放后,上、正和右(或和它们相对的面)距离中心的距离,也就是半径。 因为矩形的对称性,只需要三个分量就可以表示六个面的情况。
-
创建一个
Position节点,Space选择Object。 -
创建一个
Absolute节点,将Position的输出连进来,得到坐标的绝对值。 -
创建一个
Object节点和一个Multipty节点,将坐标的绝对值(2.)和Object的Scale相乘。
易混淆点:
在Shader中,Position节点不是指物体的坐标,而是当前正在渲染的像素点的坐标,也就是说它是一个不断变化的值。这使得它和下一步的结果是全然不同的含义。
Object节点中的Position属性才是物体的坐标。
三、获得立方体边界
这一步得到的结果是缩放*0.5的向量,用于后续判断。
- 创建一个
Multipty节点。 - 将第二步创建的
Object节点的Scale属性和0.5相乘。
四、计算距离
这一步得到的是三个值为1或0的整数,代表当前像素点在三个方向上是否接近边界。
边界判定:
当一个点与边界的距离小于指定的
Borden Width时,我们认为它是靠近边界的,也就是说它在边框线上。
- 创建一个
Subtract节点,用第三步得到的立方体边界坐标减去第二步得到的当前像素坐标,计算出每个点和x、y、z的边界的距离。 - 创建一个
Split节点,将(1.)得到的、点和三个边界的距离分解成三个分量。 - 创建三个
Step节点,将(2.)三个距离分量分别和Edge(Border Witdh)进行对比。 - 由于
Step的逻辑是输入小于阈值输出 0,否则输出 1;而实际我们需要像素和边界的距离小于Border Witdh时显示,和Step的逻辑相反,因此需要对(3.)三个结果分别应用One Minus。
五、逻辑判断
观察立方体可知,对于立方体内的任意一点,假如它在三个方向上与边界的距离已知,则有:
如果三个距离分量中有且仅有一个分量是靠近边界的,则认为它在一个面附近; 如果三个距离分量中有两个是靠近边界的,则认为它在一条边附近; 如果三个距离分量均靠近边界,则认为它在一个顶点附近。
这一步通过对比当前点在三个方向上的情况,判定当前点是否为透明。
在上一步中我们得到了三个1或0的值,只要其中有两个或以上的1,则这个点位于边框上。
- 创建两个
Add节点,将三个分量相加。 - 创建一个
Step节点,将三个分量的和与Edge进行对比。这里的Edge可以是$1-2$之间的任意浮点数。 - 创建一个
Multipty节点,将上一步的结果和Emission Color相乘,得到颜色,连入输出节点的Color。 - 将(2.)的输出连到输出节点的
Alpha节点。
基于方案二的单个对象泛光效果
在不需要全局泛光的情况下,可以对方案二的Shader进行修改以实现单个对象泛光。