Hey there,
This is pretty much a duplicate of the “GPU Particles–Stuck on shader” post, but asks a more direct question. My issue seems to be that the original shader I’m transcoding uses a Geometry shader that spits out 4 verts at a time. They represent a “motion blur” quad that is used to render a single particle (and its trajectory). The mesh is drawn in point mode, since it’s just a cloud of vertices. I get very poor results using Graphics.DrawProcedural, and still pretty bad results (a.k.a. basically noise in both cases) when I use a MeshRenderer, which is capped at 65K verts.
Is it possible to do what I want to do? Here’s the shader code (which doesn’t work)
Shader "Smoke" {
Properties {
_ShadowTex("Shadow (RGB) ", 2D) = "" {}
_Color ("Main Color", Color) = (1,1,1,1)
_PointRadius("Particle Radius", Range(0, 0.1)) = 0.005
_DeltaTime("Delta Time", Range(0, 1)) = 0.015
_centroid ("Centroid", Vector) = (0,0,0,0)
}
SubShader {
Pass{
ZWrite Off ZTest Always Cull Off Fog { Mode Off }
Blend SrcAlpha One
CGPROGRAM
#pragma target 5.0
#pragma vertex vert
#pragma geometry geom
#pragma fragment frag
#include "UnityCG.cginc"
fixed4 _Color;
float4 _centroid;
float _PointRadius;
float _DeltaTime;
StructuredBuffer<float4> particleBuffer;
StructuredBuffer<float3> particleColor;
struct vs_in {
float4 pos : SV_POSITION;
float4 col : COLOR;
float4 uv : TEXCOORD0;
};
struct gs_in {
float4 pos : SV_POSITION;
float4 col : COLOR;
float4 uv : TEXCOORD0;
float4 uv2 : TEXCOORD1;
};
struct ps_in {
float4 pos : SV_POSITION;
float4 col : COLOR;
float4 uv : TEXCOORD0;
float4 uv2 : TEXCOORD1;
};
gs_in vert (vs_in input, uint id : SV_VertexID){
gs_in output = (gs_in)0;
float3 pos = particleBuffer[id].xyz;
float3 vel = input.uv.xyz;
float3 pos2 = (pos - vel*_DeltaTime).xyz; // previous position
output.pos = mul(UNITY_MATRIX_MV, float4(pos + _centroid, 1.0f)); // eye space
output.uv = mul(UNITY_MATRIX_MV, float4(pos2, 1.0f));
// aging
float lifetime = input.uv.w;
float age = input.pos.w;
float phase = (lifetime > 0.0) ? (age / lifetime) : 1.0; // [0, 1]
output.uv2.x = phase;
float fade = 1.0 - phase;
// float fade = 1.0;
// gl_FrontColor = gl_Color;
output.col = float4(input.col.xyz, input.col.w*fade);
return output;
}
[maxvertexcount(3)]
void geom(point gs_in input[1], inout TriangleStream<ps_in> triStream){
ps_in output = (ps_in)0;
// aging
float phase = input[0].uv2.x;
float radius = _PointRadius;
// eye space
float3 pos = input[0].pos.xyz;
float3 pos2 = input[0].uv.xyz;
float3 motion = pos - pos2;
float3 dir = normalize(motion);
float len = length(motion);
float3 x = dir *radius;
float3 view = normalize(-pos);
float3 y = normalize(cross(dir, view)) * radius;
float facing = dot(view, dir);
// check for very small motion to avoid jitter
float threshold = 0.01;
if ((len < threshold) || (facing > 0.95) || (facing < -0.95)){
pos2 = pos;
x = float3(radius, 0.0, 0.0);
y = float3(0.0, -radius, 0.0);
}
//output quad
output.col = input[0].col;
output.uv = float4(0, 0, 0, phase);
output.uv2 = input[0].pos;
//output.pos = float4(pos + x + y, 1);
output.pos = mul(UNITY_MATRIX_P,float4(pos + x + y, 1));
triStream.Append(output);
output.uv = float4(0, 1, 0, phase);
output.uv2 = input[0].pos;
//output.pos = float4(pos + x - y, 1);
output.pos = mul(UNITY_MATRIX_P, float4(pos + x - y, 1));
triStream.Append(output);
output.uv = float4(1, 0, 0, phase);
output.uv2 = input[0].pos;
//output.pos = float4(pos2 - x + y, 1);
output.pos = mul(UNITY_MATRIX_P, float4(pos2 - x + y, 1));
triStream.Append(output);
//output.uv = float4(1, 1, 0, phase);
//output.uv2 = input[0].pos;
//output.pos = float4(pos2 - x - y, 1);
//output.pos = mul(UNITY_MATRIX_P, float4(pos2 - x - y, 1));
//triStream.Append(output);
}
uniform sampler2D shadowTex;
fixed4 frag (gs_in i ) : COLOR0 {
float3 N;
N.xy = i.uv.xy * float2(2.0, -2.0) + float2(-1.0, 1.0);
float r2 = dot(N.xy, N.xy);
if (r2 > 1.0) discard; // kill pixels outside circle
N.z = sqrt(1.0-r2);
float4 eyeSpacePos = i.uv;
float4 eyeSpaceSpherePos = float4(eyeSpacePos.xyz + N * _PointRadius, 1.0); // point on sphere
float4 shadowPos = mul(UNITY_MATRIX_TEXTURE0, eyeSpaceSpherePos);
float3 shadow = float3(1, 1, 1) - tex2D(shadowTex, shadowPos.xyw).xyz;
//float alpha = saturate(1.0 - r2);
float alpha = clamp((1.0 - r2), 0.0, 1.0);
alpha *= i.col.w;
//return _Color;
return float4(i.col.xyz *shadow * alpha, alpha);
}
ENDCG
}
}
Fallback Off
}