Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Shader: particle position/rotation?

Discussion in 'Shaders' started by Lex-DRL, Mar 14, 2014.

  1. Lex-DRL

    Lex-DRL

    Joined:
    Oct 10, 2011
    Posts:
    139
    I'm trying to create a shader for the Shuriken particle system. At some stage this shader needs to know the position of the particle in the particle system's object space.

    Now, the issue. Particle system emits randomly rotated geometry. Not billboards.
    I can get the position of the vertex and convert it from object space to world space... But so far I didn't find a way to acces the position of each particle. Which has to be common for all the vertices of the same particle.
    Also, as far as I can see, what Shuriken generates is a mesh of combined particles. So the entire system (all the particles) is described in it's object space and _Object2World describes only how the entire system is positioned.

    Is there some per-vertex transformation matrix that describes how each particle positioned? Either in world or object space.
     
  2. glennpow

    glennpow

    Joined:
    Jan 30, 2012
    Posts:
    56
    Hey Lex,
    did you ever find a solution for this? I have the same issue.
     
  3. Lex-DRL

    Lex-DRL

    Joined:
    Oct 10, 2011
    Posts:
    139
    I have discussed this issue a lot with our C# programmers. And we found that there is absolutely no way to get this data in shader.
    From the programming point of view, Shuriken is an extremely closed system. Unity developers just didn't provide a methods to access this data. So even if we'd like to send world position to shader as texcoord2, we just don't know these numbers at c# level.
    So the only solution is writing your own particle system component. Which is very disappointing, to say the least.
     
  4. glennpow

    glennpow

    Joined:
    Jan 30, 2012
    Posts:
    56
    I did find a solution actually. If you add a script with this to your main camera:

    Code (CSharp):
    1. voidOnPreCull() {
    2.   Shader.SetGlobalMatrix("_Camera2World", m_Camera.cameraToWorldMatrix);
    3. }
    And then these to your vertex shader (in the appropriate places):

    Code (csharp):
    1. float4x4_Camera2World;
    Code (csharp):
    1. float3 worldSpaceObjectPos = mul(_Camera2World, v.vertex).xyz;
    You get an accurate world position of the particle vertex being rendered. I'm not sure the performance penalty, but it works great!
     
  5. Lex-DRL

    Lex-DRL

    Joined:
    Oct 10, 2011
    Posts:
    139
    As far as I can see, this code will give me the world position of the particle's vertex, not the particle itself (center of the sprite).
    I can already easily get vertex positions in world space. Unity provides a list of corresponding transformation matrices.
     
  6. fherbst

    fherbst

    Joined:
    Jun 24, 2012
    Posts:
    802
    Five years later and googling leads me to this thread. Have you ever found a solution? There's now custom vertex streams that give velocity and particle center, but it seems getting local-space vertex positions is still not possible with that data.
     
  7. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    If you need the local position, you’ll have to pass in the particle system pivot or world to object matrix to the material with a c# script. Then compare or transform the world position gotten from the vertex stream.
     
  8. fherbst

    fherbst

    Joined:
    Jun 24, 2012
    Posts:
    802
    Thanks, but with that I'd only get the local position of the particle. What I want/need is the local position of each mesh particle vertex relative to the particle transform ("object space" if it wasn't inside a giant baked particle mesh).
     
    DragonCoder and albertopdli like this.
  9. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    Use instanced mesh particles then. Those work by passing a unique object to world transform for each particle.
     
  10. fherbst

    fherbst

    Joined:
    Jun 24, 2012
    Posts:
    802
    That sounds right and works on Built-in render pipeline, but unfortunately it seems to be one more thing that doesn't work on SRP / ShaderGraph. I think I'll have to report a bug about that.
     
  11. AlcoleponeHome

    AlcoleponeHome

    Joined:
    Jun 9, 2018
    Posts:
    47
    I have a related question, is there a easy way to get the particle systems world postion in the shader it uses? I want to fade particles off as they get a distance away from the systems origin, but seem unable to get that data into the shader currently.
     
  12. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    Not without c#, nope.
     
  13. AlcoleponeHome

    AlcoleponeHome

    Joined:
    Jun 9, 2018
    Posts:
    47
    cheers for the reply, that what i thought, currently writing a script to pass the info on.
     
  14. AlcoleponeHome

    AlcoleponeHome

    Joined:
    Jun 9, 2018
    Posts:
    47
    incase anyone else wants to do the same. this will set the position and direction of the gameobject the particle system component is attached too
    Code (CSharp):
    1. void OnEnable()
    2.     {
    3.         ParticleSystem ps = GetComponent<ParticleSystem>();
    4.         customData = ps.customData;
    5.         customData.enabled = true;
    6.  
    7.        
    8.      
    9.  
    10.  
    11.  
    12.         customData.SetMode(ParticleSystemCustomData.Custom1, ParticleSystemCustomDataMode.Vector);
    13.         customData.SetVectorComponentCount(ParticleSystemCustomData.Custom1, 3);
    14.  
    15.  
    16.         customData.SetMode(ParticleSystemCustomData.Custom2, ParticleSystemCustomDataMode.Vector);
    17.         customData.SetVectorComponentCount(ParticleSystemCustomData.Custom2, 3);
    18.  
    19.     }
    20.  
    21.  
    22.     void Update(){
    23.         customData.SetVector(ParticleSystemCustomData.Custom1, 0, new ParticleSystem.MinMaxCurve(this.transform.position.x));
    24.         customData.SetVector(ParticleSystemCustomData.Custom1, 1, new ParticleSystem.MinMaxCurve(this.transform.position.y));
    25.         customData.SetVector(ParticleSystemCustomData.Custom1, 2, new ParticleSystem.MinMaxCurve(this.transform.position.z));
    26.  
    27.        Vector3 Direction =  this.transform.forward;
    28.  
    29.         customData.SetVector(ParticleSystemCustomData.Custom2, 0, new ParticleSystem.MinMaxCurve(Direction.x));
    30.         customData.SetVector(ParticleSystemCustomData.Custom2, 1, new ParticleSystem.MinMaxCurve(Direction.y));
    31.         customData.SetVector(ParticleSystemCustomData.Custom2, 2, new ParticleSystem.MinMaxCurve(Direction.z));
    32.  
    33.     }
     
  15. Forberg

    Forberg

    Joined:
    Oct 27, 2018
    Posts:
    25
    Not sure if I understood the issue here correctly, but in order to access the CENTER of a single particle in shadergraph you can go to the RENDERER section of your particle system, check CUSTOM VERTEX STREAMS and add CENTER from the dropdown. It says "Center (TEXCOORD0.zw|x)" which means you can access it from the UV node in shadergraph.

    To access, add two UV nodes, one with UV0 selected, one with UV1 selected. Pick the zw component from UV0 and the x component from UV1 and combine into a vector3.

    I used it to scale particles based on their distance to a specific point, to achieve a vacuum cleaner effect with particles (scale over time wasn't cool enough because the vacuum cleaner was moving so fast)