Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question Looking for advice on how to approach this effect

Discussion in 'Shaders' started by danamuise, Aug 31, 2023.

  1. danamuise

    danamuise

    Joined:
    Sep 15, 2022
    Posts:
    20
    I'm trying to come up with a shader solution that can react to a particle system burst collision, in a way that where ever a particle collides, that objects textures will create a transparent hole that expands to the entire material over time (I've attached a sketch of the concept) What type of shader am I looking at, stencil? Is this even a shader solution? I'm only allowed to write unlit single pass shaders btw.
     

    Attached Files:

  2. danamuise

    danamuise

    Joined:
    Sep 15, 2022
    Posts:
    20
    I guess I can just document my own progress with this. Maybe someday somebody will benefit. So far, I found a script that returns a float3 for the location a single particle collides with a gameObject. I just need to feed those coords into a reveal shader somehow

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class ParticleCollide : MonoBehaviour
    6.  
    7. {
    8.     private List<ParticleCollisionEvent> collisionEvents;
    9.  
    10.     private void Start()
    11.     {
    12.         collisionEvents = new List<ParticleCollisionEvent>();
    13.     }
    14.  
    15.     private void OnParticleCollision(GameObject other)
    16.     {
    17.         // Check if the collided object has a ParticleSystem component
    18.         ParticleSystem particleSystem = other.GetComponent<ParticleSystem>();
    19.         if (particleSystem != null)
    20.         {
    21.             int numCollisionEvents = particleSystem.GetCollisionEvents(gameObject, collisionEvents);
    22.  
    23.             // Loop through each collision event
    24.             for (int i = 0; i < numCollisionEvents; i++)
    25.             {
    26.                 Vector3 collisionPosition = collisionEvents[i].intersection;
    27.                 Debug.Log("Particle from " + other.name + " collided with " + gameObject.name + " at position: " + collisionPosition);
    28.                 // Do something with the collision position, e.g., apply damage, trigger effects, etc.
    29.             }
    30.         }
    31.     }
    32. }
     
  3. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,221
    This is absolutely something a shader can solve. You'll want a shader that has an array of Vectors the length of the max number of particles you want to allow. Each of those vectors is a 2D or 3D position and a radius or time. You can have the script set the positions and game time on hit, or update the radius via the script. In the shader iterate over the array and check the distance from the current pixel position and each of the circle/sphere positions and if you're inside the radius, show the texture and skip the rest. Otherwise if after iterating through the array that pixel isn't inside any of the radii, return the solid color.

    Code (csharp):
    1. // array uniform, outside of any vertex or frag function
    2. float4 hits[8];
    3.  
    4. // vertex shader needs to pass a position to the fragment shader pass, can be just the
    5. // texture UV or an object or world space position. but the hits position and radius
    6. // needs to be in the same space.
    7.  
    8. // in frag
    9. bool visible = false;
    10. for (int index=0; index<8; index++)
    11. {
    12.   if (length(hits[index].xyz - i.worldPos) < hits[index].w)
    13.   {
    14.     visible = true;
    15.     break;
    16.   }
    17. }
    18.  
    19. if (visible)
    20.   return tex2D(_MainTex, i.uv);
    21. else
    22.   return _SolidColor;
     
  4. danamuise

    danamuise

    Joined:
    Sep 15, 2022
    Posts:
    20
    Thanks bgolus. I stumbled across a shader that somebody made, it does exactly what I'm looking for. It creates a transparent object that I can instantiate at any particle collision location and scales it up. The shader intersects the target's material and even creates a burn effect... However only one object will work on the target, the first one that colllides. Is there some part of this shader I can modify to change that? The attached image shows two of the same objects but only one affects the target.

    Code (CSharp):
    1. Shader "Custom/SurfaceDissolveShader"
    2. {
    3.     Properties
    4.     {
    5.         _OuterColor ("Outer color", Color) = (0.5, 0.5, 0.5, 1)
    6.         _InnerColor ("Inner color", Color) = (0.25, 0.25, 0.25, 1)
    7.  
    8.         _FringeTexture ("Fringe texture", 2D) = "white" {}
    9.         _FringeRadius ("Fringe radius", Float) = 0.5
    10.  
    11.         _CracksTexture ("Cracks texture", 2D) = "white" {}
    12.         _CracksRadius ("Cracks radius", Float) = 1
    13.         _CracksTextureScale ("Cracks texture scale", Float) = 1
    14.     }
    15.  
    16.     CGINCLUDE
    17.  
    18.     float4 _OuterColor;
    19.     float4 _InnerColor;
    20.  
    21.     float3 _DissolveOrigin;
    22.     float _DissolveRadius;
    23.  
    24.     sampler2D _FringeTexture;
    25.     float _FringeRadius;
    26.  
    27.     sampler2D _CracksTexture;
    28.     float _CracksRadius;
    29.     float _CracksTextureScale;
    30.      
    31.     struct Input
    32.     {
    33.         float4 color : COLOR;
    34.         float3 worldPos;
    35.         float3 worldNormal;
    36.     };
    37.      
    38.     void dissolveEffect(Input IN, inout SurfaceOutput o, float4 color)
    39.     {
    40.         o.Albedo = color;
    41.         o.Alpha = 1;
    42.  
    43.         float dist = distance(_DissolveOrigin, IN.worldPos);
    44.         clip(dist - _DissolveRadius);
    45.         if (dist < _DissolveRadius + _CracksRadius)
    46.         {
    47.             float fringeProgress = (dist - _DissolveRadius) / _CracksRadius;
    48.             float4 fringeColour = tex2D(_FringeTexture, float2(fringeProgress, 0));
    49.  
    50.             // calculate world space UVs
    51.             float2 uv = IN.worldPos.xz;
    52.             if (abs(IN.worldNormal.x) > 0.5) uv = IN.worldPos.yz;
    53.             if (abs(IN.worldNormal.z) > 0.5) uv = IN.worldPos.xy;
    54.             uv *= _CracksTextureScale;
    55.          
    56.             o.Emission = tex2D(_CracksTexture, uv) * fringeColour.rgb * fringeColour.a;
    57.         }
    58.         if (dist < _DissolveRadius + _FringeRadius)
    59.         {
    60.             float fringeProgress = (dist - _DissolveRadius) / _FringeRadius;
    61.             float4 fringeColour = tex2D(_FringeTexture, float2(fringeProgress, 0));
    62.             o.Emission += fringeColour.rgb * fringeColour.a;
    63.         }
    64.     }
    65.  
    66.     ENDCG
    67.  
    68.     SubShader
    69.     {
    70.         Tags
    71.         {
    72.             "Queue"="Transparent"
    73.             "IgnoreProjector"="True"
    74.         }
    75.         LOD 200
    76.  
    77.         Cull Front
    78.         CGPROGRAM
    79.         #pragma surface surf Lambert addshadow
    80.      
    81.         void surf (Input IN, inout SurfaceOutput o)
    82.         {
    83.             dissolveEffect(IN, o, _InnerColor);
    84.         }
    85.      
    86.         ENDCG
    87.  
    88.         //Cull Back
    89.         CGPROGRAM
    90.         #pragma surface surf Lambert addshadow
    91.      
    92.         void surf (Input IN, inout SurfaceOutput o)
    93.         {
    94.             dissolveEffect(IN, o, _OuterColor);
    95.         }
    96.      
    97.         ENDCG
    98.     }
    99.     Fallback "Diffuse"
    100. }
     

    Attached Files:

    Last edited: Sep 6, 2023
  5. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,221
    Yes ... that's what my previous post explicitly describes how to do.
     
    danamuise likes this.