Version: 2019.1
차량 배기 가스
파티클 시스템 GPU 인스턴싱

파티클 시스템의 버텍스 스트림과 스탠다드 셰이더 지원

셰이더를 직접 작성하는 데 익숙한 개발자는 렌더러 모듈 추가 옵션을 사용하여 더 광범위한 데이터를 사용자 셰이더로 전달하도록 파티클 시스템을 설정합니다.

속도, 크기 및 중앙 포지션 같은 여러 가지 빌트인 data streams 중에서 선택할 수 있습니다. 이런 스트림을 사용하면 강력한 사용자 셰이더를 만들 수 있는 기능 외에도 더 많은 일반적인 이점을 얻을 수 있습니다.

  • Tangent 스트림은 노멀 맵 파티클을 지원하는 데 사용합니다.
  • 컬러를 제거하고 탄젠트 UV2AnimBlend 스트림을 추가하여 스탠다드 셰이더를 파티클에 사용합니다.
  • 플립북 선형 텍스처 블렌딩을 간편하게 수행하려면 UV2 및 AnimBlend 스트림을 추가하고 파티클/애니메이션 알파 블렌디드 셰이더를 연결합니다. 설정 방법은 아래의 예제 스크린샷을 참조하십시오.

스크립트에서 작성 가능한 두 개의 커스텀 파티클 데이터 스트림(ParticleSystemVertexStreams.Custom1ParticleSystemVertexStreams.Custom2)도 있습니다. 이 두 스트림을 사용하려면 SetCustomParticleDataGetCustomParticleData를 데이터 배열과 함께 호출합니다. 다음 두 가지 방법으로 가능합니다.

  • 사용자 데이터를 파티클에 연결(예를 들어, 각 파티클에 “health” 값 연결)하여 스크립트에서 커스텀한 동작을 만듭니다.
  • 두 커스텀 스트림 중 하나를 추가함으로써 다른 모든 스트림과 동일한 방법으로 셰이더로 보내 이 데이터를 셰이더에 전달합니다(ParticleSystemRenderer.EnableVertexStreams 참조). 첫 번째 예제를 좀 더 업그레이드해서 게임 로직을 스크립트 기반으로 제어하는 것 뿐만 아니라 비쥬얼 이펙트 또한 체력 속성을 이용하여 스크립트 기반으로 제어가 가능합니다.

버텍스 스트림을 추가할 때, Unity는 셰이더에서 올바른 데이터를 읽는 데 도움이 되는 정보를 각 항목 옆에 대괄호로 묶어서 제공합니다.

괄호 안에 있는 각 항목은 셰이더에서 지정해야 하는 버텍스 셰이더 입력에 해당합니다. 이 설정의 올바른 입력 구조는 다음과 같습니다.

            struct appdata_t {
                            float4 vertex : POSITION;
                            float3 normal : NORMAL;
                            fixed4 color : COLOR;
                            float4 texcoords : TEXCOORD0;
                            float texcoordBlend : TEXCOORD1;
                        };

UV와 UV2가 모두 TEXCOORD0의 각기 다른 부분에 전달되는데 단일 선언으로 두 개를 동시에 사용가능합니다. 셰이더에서 각각에 액세스하려면 xy 및 zw 스위즐을 사용합니다. 그러면 버텍스 데이터를 효율적으로 패킹할 수 있습니다.

다음은 애니메이션화 플립북 셰이더의 예제입니다. 이 예제에서는 디폴트 입력(Position, Normal, Color, UV)을 사용하지만, 두 번째 UV 시스템(UV2)과 플립북 프레임 정보(AnimBlend)의 추가 스트림 두 개도 사용합니다.

Shader "Particles/Anim Alpha Blended" {
Properties {
    _TintColor ("Tint Color", Color) = (0.5,0.5,0.5,0.5)
    _MainTex ("Particle Texture", 2D) = "white" {}
    _InvFade ("Soft Particles Factor", Range(0.01,3.0)) = 1.0
}

Category {
    Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "PreviewType"="Plane" }
    Blend SrcAlpha OneMinusSrcAlpha
    ColorMask RGB
    Cull Off Lighting Off ZWrite Off

    SubShader {
        Pass {
        
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma target 2.0
            #pragma multi_compile_particles
            #pragma multi_compile_fog
            
            #include "UnityCG.cginc"

            sampler2D _MainTex;
            fixed4 _TintColor;
            
            struct appdata_t {
                float4 vertex : POSITION;
                fixed4 color : COLOR;
                float4 texcoords : TEXCOORD0;
                float texcoordBlend : TEXCOORD1;
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };

            struct v2f {
                float4 vertex : SV_POSITION;
                fixed4 color : COLOR;
                float2 texcoord : TEXCOORD0;
                float2 texcoord2 : TEXCOORD1;
                fixed blend : TEXCOORD2;
                UNITY_FOG_COORDS(3)
                #ifdef SOFTPARTICLES_ON
                float4 projPos : TEXCOORD4;
                #endif
                UNITY_VERTEX_OUTPUT_STEREO
            };
            
            float4 _MainTex_ST;

            v2f vert (appdata_t v)
            {
                v2f o;
                UNITY_SETUP_INSTANCE_ID(v);
                UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); 
                o.vertex = UnityObjectToClipPos(v.vertex);
                #ifdef SOFTPARTICLES_ON
                o.projPos = ComputeScreenPos (o.vertex);
                COMPUTE_EYEDEPTH(o.projPos.z);
                #endif
                o.color = v.color * _TintColor;
                o.texcoord = TRANSFORM_TEX(v.texcoords.xy,_MainTex);
                o.texcoord2 = TRANSFORM_TEX(v.texcoords.zw,_MainTex);
                o.blend = v.texcoordBlend;
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }

            sampler2D_float _CameraDepthTexture;
            float _InvFade;
            
            fixed4 frag (v2f i) : SV_Target
            {
                #ifdef SOFTPARTICLES_ON
                float sceneZ = LinearEyeDepth (SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture, UNITY_PROJ_COORD(i.projPos)));
                float partZ = i.projPos.z;
                float fade = saturate (_InvFade * (sceneZ-partZ));
                i.color.a *= fade;
                #endif
                
                fixed4 colA = tex2D(_MainTex, i.texcoord);
                fixed4 colB = tex2D(_MainTex, i.texcoord2);
                fixed4 col = 2.0f * i.color * lerp(colA, colB, i.blend);
                UNITY_APPLY_FOG(i.fogCoord, col);
                return col;
            }
            ENDCG 
        }
    }   
}
}


표면 셰이더도 이 시스템과 함께 사용할 수 있지만, 주의해야 할 사항이 몇 가지 더 있습니다.

  • surface 함수 입력 구조는 버텍스 셰이더 입력 구조와 동일하지 않습니다. 버텍스 셰이더 입력 구조를 직접 제공해야 합니다. appdata_particles라는 구조를 사용하는 아래 예제를 참조하십시오.
  • 표면 셰이더를 빌드하면 이름이 특정 토큰으로 시작되는 변수가 자동으로 처리됩니다. 이 중 가장 중요한 것은 uv입니다. 자동 처리로 인해 문제가 발생하지 않도록 하려면 UV 입력에 각각 다른 이름을 지정해야 합니다(예를 들어, “texcoord”).

다음은 첫 예제와 동일한 기능을 표면 셰이더에 적용한 예제입니다.

Shader "Particles/Anim Alpha Blend Surface" {
    Properties {
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _Glossiness ("Smoothness", Range(0,1)) = 0.5
        _Metallic ("Metallic", Range(0,1)) = 0.0
    }
    SubShader {
        Tags {"Queue"="Transparent" "RenderType"="Transparent"}
        Blend SrcAlpha OneMinusSrcAlpha
        ZWrite off
        LOD 200
        
        CGPROGRAM
        // Physically based Standard lighting model, and enable shadows on all light types
        #pragma surface surf Standard alpha vertex:vert

        // Use shader model 3.0 target, to get nicer looking lighting
        #pragma target 3.0

        sampler2D _MainTex;

         struct appdata_particles {
            float4 vertex : POSITION;
            float3 normal : NORMAL;
            float4 color : COLOR;
            float4 texcoords : TEXCOORD0;
            float texcoordBlend : TEXCOORD1;
            };


        struct Input {
            float2 uv_MainTex;
            float2 texcoord1;
            float blend;
            float4 color;
        };


        void vert(inout appdata_particles v, out Input o) {
            UNITY_INITIALIZE_OUTPUT(Input,o);
            o.uv_MainTex = v.texcoords.xy;
            o.texcoord1 = v.texcoords.zw;
            o.blend = v.texcoordBlend;
            o.color = v.color;
          }


        half _Glossiness;
        half _Metallic;
        fixed4 _Color;


        void surf (Input IN, inout SurfaceOutputStandard o) {
            fixed4 colA = tex2D(_MainTex, IN.uv_MainTex);
            fixed4 colB = tex2D(_MainTex, IN.texcoord1);
            fixed4 c = 2.0f * IN.color * lerp(colA, colB, IN.blend) * _Color;
                 
            o.Albedo = c.rgb;
            // Metallic and smoothness come from slider variables
            o.Metallic = _Metallic;
            o.Smoothness = _Glossiness;
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}


차량 배기 가스
파티클 시스템 GPU 인스턴싱