- Home /
Particle Shader help
Hi,
I'm starting to learn shaders and wanted to create my own particle effect shader.
The only thing I want to pass to the shader is the frame time (Time.deltaTime) and the shader will do the rest of the work (Transformation and modifying the alpha value)
I want to calculate the age of the particle by setting a lifetime (LT) and a current age (Age) then by doing LT - Age I can find out how 'old' the particle is, the older the particle the higher the alpha value. When alpha reaches 1 or the fragment is invisible I want to set the Age back to 0. The position of the particle will be definied by the Age also, if the Age is 0 the particle will be ontop of the emitter.
I would like to do all transformation in the vertex shader and all alpha value modifyin gin the fragment shader.
I don't understand the shaders very well and was hoping someone could offer some assistance in how to get my method working. This is the second shader I'm trying to write so I'm still trying to understand the syntax :)
Here's what I have so far
Shader "Custom/ParticalShader"
{
Properties
{
_Speed ("Particle Speed", Range (0,100)) = 1
}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
float _Speed;
struct v2f {
float4 pos : SV_POSITION;
float3 color : COLOR0;
};
v2f vert (appdata_base v)
{
float t = frac(v.vertex.z + _Speed * _Time);
float s = pow(t, 1);
v2f o;
o.pos.x = 20 * s * sin(62.0 * v.vertex.z);
o.pos.z = 20 * s * cos(163.0 * v.vertex.z);
o.pos.y = t * 80;
//o.pos += 7.8 * (v.vertex.x * UNITY_MATRIX_I_V, + v.vertex.y * UNITY_MATRIX_I_V).xyz;
//o.pos += vec4(0,0,0,0);
o.pos = mul (UNITY_MATRIX_VP, o.pos);
o.color = 1.0 - t;
return o;
}
half4 frag (v2f i) : COLOR
{
return half4 (i.color, 1);
}
ENDCG
}
}
}
I'm reading up on this as I post it but I would still like to know the community's opinion on how to do this :)
Thanks in advance
Currently my particle shader works but is hard to see without billboarding, trying to implement this now
Cool project!
I have a couple more questions for you... What is instancing vertices? Do you do that in c# with a single procedural mesh? Is this attached to each individual particle? Is each particle a mesh then?
You might want to look into tessellation shaders in order to vastly improve performance of your particle system. The idea is that you could have 1 shader create all your particle geo for you, for basically free, and much faster than doing it on the cpu. I have little experience with this, but the concept is enticing.
FYI Raising a number to the power of 1 does nothing. But I assume you know that...
Also you mention setting the alpha based on age, but then your alpha is being set to 1. Have you not gotten to the fragment shader yet? Using color to pass this info from the vertex to the fragment shader should suffice, though I recommend using each channel separately so you can send 4 floats of data across, if you need. So maybe you can use rgb for velocity, and a for age?
Billboarding is just some matrix math. Here's a glsl solution I found, may be of use to you:
gl_Position = gl_Projection$$anonymous$$atrix
* (gl_$$anonymous$$odelView$$anonymous$$atrix * vec4(0.0, 0.0, 0.0, 1.0)
+ vec4(gl_Vertex.x, gl_Vertex.y, 0.0, 0.0));
Hope that helped!
This was some awesome help, Although I am making my particle system for $$anonymous$$obile so I don't have access to tessellation, I do however have access to transform feedback (Although Unity doesn't seem to support this directly).
To answer some of your questions
I have several Quads and attatch the shader to each quad (This achieves 1 draw call but only by batching, I would like to get rid of this and make it 1 draw call with no batching)
Hehe yeah I did know that I was just playing around with some variables :)
Correct I haven't got to the fragment shader yet.
Using the colour channgels to pass data is awesome I'm definitely going to try to impliment this. Thanks :)
I managed to sort the billboarding to some extent :) (For anyone else looking at this question)
v2f vert (appdata_base v)
{
float t = frac(v.vertex.z + _Speed * _Time);
float s = pow(t, 1);
float3 eyeVector = ObjSpaceViewDir( v.vertex );
float3 upVector = float3(0,1,0);
float3 sideVector = normalize(cross(eyeVector,upVector));
v2f o;
o.pos.x = 20 * s * sin(62.0 * v.vertex.z);
o.pos.z = 20 * s * cos(163.0 * v.vertex.z);
o.pos.y = t * _Height;
o.pos.xyz += 7.8 * (v.vertex.x * sideVector + v.vertex.y * upVector).xyz;
o.pos = mul (UNITY_$$anonymous$$ATRIX_VP, o.pos);
o.color = 1.0 - t;
return o;
}
It is was OP_toss said but in the unity syntax :)
I did something similar to what you are doing but ins$$anonymous$$d of having a quad a had an empty game object and added a mesh with a single point in order to use a material that implemented a vertex/geometry/fragment shader. You could try something like having a collection of vertices (Vector4) were the w component represents the alpha over time which gets set to a separate variable in the vertex shader and passed to the geometry shader. You could have something like this
struct GS_INPUT
{
float4 pos : POSITION;
float alphaVal : TEXCOORD0;
};
// Vertex Shader ------------------------------------------------
GS_INPUT VS_$$anonymous$$ain(appdata_full v)
{
GS_INPUT output = (GS_INPUT)0;
output.pos = mul(_Object2World, float4(v.vertex.xyz, 1));
output.texCoord = float2(0, 0);
output.alphaVal = v.vertex.w; // this will get pass to the GS and then the FS to do transparency over time
return output;
}
struct FS_INPUT
{
float2 texCoord : TEXCOORD0;
float alphaVal : TEXCOORD1;
};
[maxvertexcount(4)] // this indicates how many vertices will be output (4 for quad)
// point indicates we are sending one vertex at a time to the GS
// inout is the format on how the GPU should read the output, in this case triangle strip
void GS_$$anonymous$$ain(point GS_INPUT p[1], inout TriangleStream triStream)
{
// here you can use some vector math to create a quad that is always facing the camera using Unity shader constants or you can pass the camera position all the way here this includes normals if you want to get fancy and have them react to light as well as uv coordinates if you have a texture
}
Your answer
Follow this Question
Related Questions
Limit particle shader / discard from certain worldpos 1 Answer
PS Custom Vertex Streams to Particle Trail 0 Answers
How to convert Legacy/Particles/Alpha Blended to Standard?And How to configure the standard option? 0 Answers
Shader tiling error 0 Answers
My particles glow at night how can I stop the glowing 0 Answers