我希望为发射立方体网格的粒子系统创建一个不发光的着色器,这样每个发射的网格周围都有一个硬黑色轮廓。
这是大纲的通行证(在 Cg 中):
struct appdata {
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f {
float4 pos : POSITION;
float4 color : COLOR;
};
uniform float _Outline;
uniform float4 _OutlineColor;
v2f vert(appdata v) {
v2f o;
v.vertex *= ( 1 + _Outline);
o.pos = UnityObjectToClipPos(v.vertex);
o.color = _OutlineColor;
return o;
}
half4 frag(v2f i) :COLOR { return i.color; }
(在这之后是一个简单的过程来渲染网格本身的未照亮的几何体......)
如您所见,我们只是向外拉伸顶点......但是从什么方向拉伸?
对于单个立方体网格,着色器工作得很好:
但是,当应用于发射立方体网格的粒子系统时,着色器会崩溃:
我怀疑线
v.vertex *= ( 1 + _Outline);
从object中心向外拉伸顶点,而不是网格中心。
有人有替代着色器或了解如何解决此问题吗?
谢谢, rbjacob
事实证明我误解了这个问题。当访问顶点的
POSITION
语义时,您将获得 世界空间 中发射粒子的顶点;因此,通过乘法拉伸顶点实际上只是将它们缩放到远离世界中心的位置。
要访问相对于每个粒子的顶点,我们必须能够从着色器内访问每个粒子的网格中心。为此,我们在粒子系统的渲染器模块内启用“自定义顶点流”,然后按 + 按钮添加中心流。
现在我们可以从着色器访问
TEXCOORD0
(或粒子渲染器GUI中中心流右侧指定的任何内容)以获取世界空间中的网格中心。然后我们从每个顶点位置减去网格中心,向外缩放,然后将网格中心添加回来。瞧,每个粒子都有一个轮廓。
以下是大纲通道的最终 vert 和 frag 片段:
struct appdata {
float3 vertex : POSITION;
float4 color : COLOR;
float3 center : TEXCOORD0;
};
struct v2f {
float4 pos : POSITION;
float4 color : COLOR;
float3 center : TEXCOORD0;
};
uniform float _Outline;
uniform float4 _OutlineColor;
v2f vert(appdata v) {
v2f o;
o.center = v.center;
float3 vert = v.vertex - v.center;
vert *= ( 1 + _Outline);
v.vertex = vert + v.center;
o.pos = UnityObjectToClipPos(v.vertex);
o.color = _OutlineColor;
return o;
}
half4 frag(v2f i) :COLOR { return i.color; }
TLDR: 启用顶点流,为粒子中心添加流,并在着色器中访问该值以向外缩放各个顶点。
我怀疑线
从对象中心向外拉伸顶点,而不是网格中心。v.vertex *= ( 1 + _Outline);
那是正确的。或者大部分是正确的(粒子系统将所有粒子组合到一个运行时网格中,这就是着色器所应用的内容,而不是底层的单个粒子网格,这并不明显)。在非凸网格(也不是粒子)上尝试轮廓着色器:您会发现凹入部分不会具有所需的轮廓,这证实了您的怀疑。
几年前我写了这个着色器,因为我能找到的唯一免费的生成轮廓的着色器要么是(a)不是免费的,要么是(b)“只是将其缩放得更大”的品种。它仍然存在问题(例如在大厚度值时变得锯齿状和奇怪),但我始终无法令人满意地解决它们。它使用几何通道将源网格的边缘转换为面向相机的四边形,然后使用模板魔法仅渲染轮廓部分。
但是我不确定该着色器在应用于粒子时是否会起作用。我怀疑不加修改就可以,但你可以尝试一下。
你是如何创造两种颜色的? 我正在尝试在 Shader Graph 中复制您的代码 - 我正在向片段部分添加颜色,并且它为整个网格着色(在代码期间更改大小的网格)。