Unity粒子轮廓着色器
Unity particle outline shader
我想为发射立方体网格的粒子系统创建一个不发光的着色器,这样每个发射的网格周围都有一个硬黑色轮廓。
这里是大纲的pass(in 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);
从 对象 中心向外拉伸顶点,而不是网格中心。
是否有人有替代着色器或关于如何解决此问题的见解?
谢谢,
雅各布
My suspicion is that the line v.vertex *= ( 1 + _Outline);
stretches the vertices outward from the object center, not the mesh center.
没错。或者大部分是正确的(粒子系统将所有粒子组合到一个运行时网格中,这就是您的着色器所应用的对象,而不是底层的单个粒子网格,这并不明显)。在非凸面网格(也不是粒子)上尝试轮廓着色器:您会发现凹面部分没有所需的轮廓,证实了您的怀疑。
我 wrote this shader 几年前,因为我能找到的唯一免费着色器生成的轮廓要么 (a) 不是免费的,要么 (b) "just scale it bigger" 种类。它仍然存在问题(例如在大厚度值时变得锯齿状和怪异),但我一直无法令人满意地解决它们。它使用几何通道将源网格的边缘变成面向相机的四边形,然后使用模板魔术仅渲染轮廓部分。
但是我不确定该着色器在应用于粒子时是否会起作用。我怀疑它会在没有修改的情况下出现,但您可以随意试一试。
原来是我理解错了问题。当访问顶点的 POSITION
语义时,您将获得 world space 中发射粒子的顶点;因此,通过相乘来拉伸顶点实际上只是将它们从世界中心缩放。
要访问与每个粒子相关的顶点,我们必须能够从着色器中访问每个粒子的网格中心。为此,我们在粒子系统的渲染器模块中启用 "Custom Vertex Streams",然后按 + 按钮添加中心流。
现在我们可以从着色器访问 TEXCOORD0
(或粒子渲染器 GUI 中中心流右侧指定的任何内容)以获取世界 space 中的网格中心。然后我们从每个顶点位置减去网格中心,向外缩放,然后将网格中心加回去。瞧,每个粒子都有一个轮廓。
以下是轮廓通道的最终 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:启用顶点流,为粒子中心添加流,并在着色器中访问该值以向外缩放单个顶点。
我想为发射立方体网格的粒子系统创建一个不发光的着色器,这样每个发射的网格周围都有一个硬黑色轮廓。
这里是大纲的pass(in 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);
从 对象 中心向外拉伸顶点,而不是网格中心。
是否有人有替代着色器或关于如何解决此问题的见解?
谢谢, 雅各布
My suspicion is that the line
v.vertex *= ( 1 + _Outline);
stretches the vertices outward from the object center, not the mesh center.
没错。或者大部分是正确的(粒子系统将所有粒子组合到一个运行时网格中,这就是您的着色器所应用的对象,而不是底层的单个粒子网格,这并不明显)。在非凸面网格(也不是粒子)上尝试轮廓着色器:您会发现凹面部分没有所需的轮廓,证实了您的怀疑。
我 wrote this shader 几年前,因为我能找到的唯一免费着色器生成的轮廓要么 (a) 不是免费的,要么 (b) "just scale it bigger" 种类。它仍然存在问题(例如在大厚度值时变得锯齿状和怪异),但我一直无法令人满意地解决它们。它使用几何通道将源网格的边缘变成面向相机的四边形,然后使用模板魔术仅渲染轮廓部分。
但是我不确定该着色器在应用于粒子时是否会起作用。我怀疑它会在没有修改的情况下出现,但您可以随意试一试。
原来是我理解错了问题。当访问顶点的 POSITION
语义时,您将获得 world space 中发射粒子的顶点;因此,通过相乘来拉伸顶点实际上只是将它们从世界中心缩放。
要访问与每个粒子相关的顶点,我们必须能够从着色器中访问每个粒子的网格中心。为此,我们在粒子系统的渲染器模块中启用 "Custom Vertex Streams",然后按 + 按钮添加中心流。
现在我们可以从着色器访问 TEXCOORD0
(或粒子渲染器 GUI 中中心流右侧指定的任何内容)以获取世界 space 中的网格中心。然后我们从每个顶点位置减去网格中心,向外缩放,然后将网格中心加回去。瞧,每个粒子都有一个轮廓。
以下是轮廓通道的最终 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:启用顶点流,为粒子中心添加流,并在着色器中访问该值以向外缩放单个顶点。