I wish to create an unlit shader for a particle system that emits cube meshes, such that each emitted mesh has a hard black outline around it.
Here is the pass for the outline (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; }
(And after this is a simple pass to render the unlit geometry of the mesh itself...)
As you can see, we are simply stretching the vertices outward... but from what?
For a single cube mesh, the shader works perfectly:
However, when applied to a particle system emitting cube meshes, the shader breaks down:
My suspicion is that the line v.vertex *= ( 1 + _Outline);
stretches the vertices outward from the object center, not the mesh center.
Does anyone have a replacement shader or insight on how to fix this problem?
Thanks, rbjacob
It turns out that I misconstrued the problem. When accessing the POSITION
semantic of the vertices, you are getting the vertices of the emitted particles in world space; therefore, stretching the vertices by multiplying is actually just scaling them away from the world center.
To access the vertices relative to each particle, we must be able to access each particle's mesh center from within the shader. To do this, we enable "Custom Vertex Streams" inside the Renderer module of the particle system and press the + button to add the Center stream.
Now we can access TEXCOORD0
(or whatever is specified to the right of the Center stream in the particle renderer GUI) from the shader to get the mesh center in world space. Then we subtract the mesh center from each vertices position, scale outward, and add the mesh center back. And voila, each particle has an outline.
Here are the final vert and frag snippets for the outline pass:
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: Enable vertex streams, add a stream for the particle center, and access this value in the shader to scale individual vertices outward.