霹靂星球爆炸了

這一篇來講講粒子怎麼控制,在 Unity 的粒子系統裡,其實每一顆粒子都可以被手動控制,這裡我們做一個範例來看看。

voxs.mov

在這個例子,我們手動把粒子設定在我們要的位置,最簡單就是把它排成一個的正方體。然後再給它一個隨機的方向速度,讓它噴出去。

設定

以下是我們對粒子系統的設定:

  • PlayOnAwake 是關閉的。
  • Collision 是打開的讓它有碰撞。
  • Renderer 把它設定成 Mesh Cube,因為我們會對粒子改顏色,所以建立一個 Material 再寫一個簡單有頂點色的 Shader 給 Renderer。

除了以上三個,其它功能的都是關閉不勾選的。

操作流程

我們操作粒子的流程如下:

  1. ParticleSystem.MainModule.maxParticles 設定粒子的最大噴發數
  2. ParticleSystem.Emit 噴發粒子
  3. ParticleSystem.GetParticles 取出所有可用粒子
  4. ParticleSystem.Particle.position 設定粒子位置
  5. ParticleSystem.Particle.startSize 設定粒子大小
  6. ParticleSystem.Particle.startColor 設定粒子顏色
  7. ParticleSystem.Particle.startLifetime 設定定子存活時間
  8. ParticleSystem.SetParticles 把設定過的粒子塡回粒子系

要注意的是 ParticleSystem.GetParticles 時,傳進去的 Array 必需要先 new 出來,不然會取不到粒子的 array。

按鍵輸入

為了能看清楚粒子排出來的結果,我們寫成按下 A 鍵時會建立粒子並把 ParticleSystem.MainModule.simulationSpeed 設為 0 讓它停留在原位;然後按下 B 鍵時再手動把 simulationSpeed 設 1 讓它模擬下去,爆炸開來。

大約就這樣子,簡簡單的就完成了!

我們也可以在 LateUpdate 每個 frame 對粒子各種變化的操作,如對位置的運算加入數學公式,粒子就會依公式的結果顯示在結果的位置。

以下就是程式及 Shader

CS:

//Arc https://arclee0117.wordpress.com
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ParticleExp : MonoBehaviour {


    public ParticleSystem m_ParticleSystem;
    ParticleSystem.Particle[] m_Particles;

    public uint m_DimX = 1;
    public uint m_DimY = 1;
    public uint m_DimZ = 1;
    public float m_Size = 1;
    public float m_ForceScale = 1;
    bool m_CreateParticle = false;
	// Use this for initialization
	void Start ()
    {
	}
	
    void Update()
    {

        if (Input.GetKeyUp(KeyCode.B))
        {
            // 開始。
            ParticleSystem.MainModule mm = m_ParticleSystem.main;
            mm.simulationSpeed = 1.0f;
        }
        else if (Input.GetKeyUp(KeyCode.A))
        {
            // 設定。
            SetupParticle();   
        }

    }

    // 把粒子設定成目標的型狀。
    void SetupParticle()
    {
        ParticleSystem.MainModule mm = m_ParticleSystem.main;
        // 設定數量。
        mm.maxParticles = (int)(m_DimX * m_DimY * m_DimZ);

        // 清空,噴發。
        m_ParticleSystem.Clear();
        m_ParticleSystem.Emit(m_ParticleSystem.main.maxParticles);

        if (m_Particles == null || m_Particles.Length != m_ParticleSystem.main.maxParticles)
        {
            m_Particles = new ParticleSystem.Particle[m_ParticleSystem.main.maxParticles];
        }

        // 取出粒子。
        // 因為才剛噴發而己,所以一定都是 alive 的粒子,可以拿來操作。
        m_ParticleSystem.GetParticles(m_Particles);

        // 接下來就假設我們要噴一個大立方體的正方型。
        Vector3 tempV3 = Vector3.zero;
        Color tempColor = Color.black;
        Vector3 centerPos = Vector3.zero;
        centerPos.x = -m_DimX / 2;
        centerPos.y = -m_DimY / 2;
        centerPos.z = -m_DimZ / 2;
        for (uint x = 0; x < m_DimX; x++)
        {
            for (uint y = 0; y < m_DimY; y++)
            {
                for (uint z = 0; z < m_DimZ; z++)
                {
                    uint idx = (x * m_DimY * m_DimZ) + (y * m_DimZ) + z;
                    // 設定位置。
                    tempV3.x = centerPos.x + x;
                    tempV3.y = centerPos.y + y;
                    tempV3.z = centerPos.z + z;
                    m_Particles[idx].position = tempV3 * m_Size;

                    //設定顏色。
                    tempColor.r = (float)x / (float)m_DimX;
                    tempColor.g = (float)y / (float)m_DimY;
                    tempColor.b = (float)z / (float)m_DimZ;
                    m_Particles[idx].startColor = tempColor;

                    // 設定大小。
                    m_Particles[idx].startSize = m_Size;

                    // 噴出的方向。
                    tempV3.x = Random.Range(-1.0f, 1.0f);
                    tempV3.y = Random.Range(-1.0f, 1.0f);
                    tempV3.z = Random.Range(-1.0f, 1.0f);
                    m_Particles[idx].velocity = tempV3 * m_ForceScale;

                    m_Particles[idx].startLifetime = 10;
                }
            }
        }

        // 把改過的粒子設定回粒子系統裡。
        m_ParticleSystem.SetParticles(m_Particles, m_Particles.Length);

        // 先停止,等一下再手動操作。
        mm.simulationSpeed = 0;
    }
}

Shader:

//Arc https://arclee0117.wordpress.com
Shader "Custom/meshshader" {

	SubShader {
		Tags { "RenderType"="Opaque" }
		LOD 200
		
		CGPROGRAM
		// Physically based Standard lighting model, and enable shadows on all light types
		#pragma surface surf Standard fullforwardshadows vertex:vert 

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

		sampler2D _MainTex;

		struct Input {
		    float3 vertColor;
		};

		struct InOutData
		{
			float4 vertex    : POSITION;  // The vertex position in model space.
			float3 normal    : NORMAL;    // The vertex normal in model space.
			float4 color     : COLOR;     // Per-vertex color
		};

		void vert(inout InOutData v, out Input o)
		 {
		    UNITY_INITIALIZE_OUTPUT(Input, o);
		    o.vertColor = v.color;
		}

		void surf (Input IN, inout SurfaceOutputStandard o) {
			o.Albedo = IN.vertColor;;
		}
		ENDCG
	}
	FallBack "Diffuse"
}

不要吐草我:"霹靂星球應該不是方型的吧!"

2 thoughts on “霹靂星球爆炸了

發表留言