๐ŸซงArt_025 Sphere Surface Particle [ํŒŒํ‹ฐํด ์‹œ์Šคํ…œ]

BamgasiJMยท2026๋…„ 4์›” 17์ผ

Unity GenArt

๋ชฉ๋ก ๋ณด๊ธฐ
36/41
post-thumbnail

Sphere Surface Particle System ๊ตฌํ˜„ ๊ฐ€์ด๋“œ

  • ๊ตฌ์ฒด ํ‘œ๋ฉด ์œ„๋ฅผ ์›€์ง์ด๋Š” ํŒŒํ‹ฐํด ์‹œ์Šคํ…œ์„ ๊ตฌํ˜„
  • ๊ธฐ์กด ํŒŒํ‹ฐํด ์‹œ์Šคํ…œ์˜ ๋™์ž‘ ๋ฐฉ์‹์„ ์ปค์Šคํ…€ ์Šคํฌ๋ฆฝํŠธ๋กœ ์ œ์–ด

1. ๋™์ž‘ ์›๋ฆฌ ๋ฐ ๊ตฌํ˜„

1.1 ๋™์ž‘ ์›๋ฆฌ

์ด ํŒŒํ‹ฐํด ์‹œ์Šคํ…œ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํ•ต์‹ฌ ๋กœ์ง์œผ๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

1. ์ดˆ๊ธฐ ๋ฐฐ์น˜ (Initialization)

  • Random.onUnitSphere๋ฅผ ์‚ฌ์šฉํ•ญ์—ฌ ๋‹จ์œ„ ๊ตฌ(๋ฐ˜์ง€๋ฆ„ 1) ํ‘œ๋ฉด์˜ ๋žœ๋คํ•œ ์ขŒํ‘œ๋ฅผ ์ƒ์„ฑ.
  • ์—ฌ๊ธฐ์— ์‚ฌ์šฉ์ž๊ฐ€ ์„ค์ •ํ•œ sphereRadius๋ฅผ ๊ณฑํ•˜์—ฌ ์›ํ•˜๋Š” ํฌ๊ธฐ์˜ ๊ตฌ ํ‘œ๋ฉด ์œ„์— ํŒŒํ‹ฐํด์„ ๋ฐฐ์น˜.

2. ํ‘œ๋ฉด ๊ตฌ์† (Surface Constraint)

  • ํŒŒํ‹ฐํด์ด ์›€์ง์ผ ๋•Œ๋งˆ๋‹ค ์œ„์น˜ ๋ฒกํ„ฐ๋ฅผ normalized(์ •๊ทœํ™”)ํ•˜์—ฌ ๋ฐฉํ–ฅ ๋ฒกํ„ฐ๋งŒ ์ถ”์ถœ.
  • ์ •๊ทœํ™”๋œ ๋ฒกํ„ฐ์— sphereRadius๋ฅผ ๋‹ค์‹œ ๊ณฑํ•จ์œผ๋กœ์จ, ํŒŒํ‹ฐํด์ด ํ•ญ์ƒ ๊ตฌ์˜ ํ‘œ๋ฉด(์›์ ์—์„œ ์ผ์ •ํ•œ ๊ฑฐ๋ฆฌ) ์œ„์— ์œ„์น˜ํ•˜๋„๋ก ๊ฐ•์ œํ•จ.

3. ๋…ธ์ด์ฆˆ ๊ธฐ๋ฐ˜ ์šด๋™ (Noise-based Motion)

  • Mathf.PerlinNoise๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ ํŒŒํ‹ฐํด์— ๊ณ ์œ ํ•˜๋ฉด์„œ๋„ ์ž์—ฐ์Šค๋Ÿฌ์šด ์˜คํ”„์…‹ ๊ฐ’์„ ์ƒ์„ฑ.
  • ํŒŒํ‹ฐํด์˜ ์ธํ…์„œ(i)์— ๊ณ ์œ ํ•œ ์†Œ์ˆ˜ ๊ณ„์ˆ˜๋ฅผ ๊ณฑํ•˜์—ฌ ์‹œ๋“œ ๊ฐ’์„ ๋‹ค๋ฅด๊ฒŒ ์„ค์ •ํ•จ์œผ๋กœ์จ, ๊ฐ ํŒŒํ‹ฐํด์ด ์„œ๋กœ ๋‹ค๋ฅธ ํŒจํ„ด์œผ๋กœ ์›€์ง์ด๋„๋ก ํ•จ.
  • ์ƒ์„ฑ๋œ ๋…ธ์ด์ฆˆ ์˜คํ”„์…‹์„ ํ˜„์žฌ ์œ„์น˜์— ๋”ํ•œ ๋’ค, ๋‹ค์‹œ ์ •๊ทœํ™” ๋ฐ ๋ฐ˜์ง€๋ฆ„ ์ ์šฉ ๊ณผ์ •์„ ๊ฑฐ์ณ ๊ตฌ ํ‘œ๋ฉด์„ ๋”ฐ๋ผ ํ๋ฅด๋Š” ๋“ฏํ•œ ์›€์ง์ž„์„ ๊ตฌํ˜„.

4. ์ˆ˜๋ช… ๊ด€๋ฆฌ (Lifetime Management)

  • LateUpdate์—์„œ ๋งค ํ”„๋ ˆ์ž„ remainingLifetime์„ ๊ฐ•์ œ๋กœ lifetime์œผ๋กœ ์žฌ์„ค์ •.
  • ์ด๋ฅผ ํ†ตํ•ด ํŒŒํ‹ฐํด์ด ์†Œ๋ฉธํ•˜์ง€ ์•Š๊ณ  ์˜์›ํžˆ ์›€์ง์ด๋„๋ก ์œ ์ง€.

1.2 ๊ตฌํ˜„ ๋‹จ๊ณ„ (Unity Editor ์„ค์ •)

์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ ์šฉํ•˜๊ธฐ ์ „, Unity ์—๋””ํ„ฐ์—์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์„ค์ •ํ•ด์•ผ ํ•จ.

๋‹จ๊ณ„ 1. ๋นˆ ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ ์ƒ์„ฑ ํ›„ ์Šคํฌ๋ฆฝํŠธ ์ฒจ๋ถ€

  1. Hierarchy ์ฐฝ์—์„œ ์šฐํด๋ฆญ > Create Empty๋ฅผ ์„ ํƒํ•˜์—ฌ ๋นˆ ์˜ค๋ธŒ์ ํŠธ๋ฅผ ์ƒ์„ฑ.
  2. ์ƒ์„ฑ๋œ ์˜ค๋ธŒ์ ํŠธ์— Particle System ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ถ”๊ฐ€ (Add Component > Particle System).
  3. GenerativeSphereParticles.cs๋ฅผ ํ”„๋กœ์ ํŠธ์— ์ถ”๊ฐ€ํ•˜๊ณ , ์˜ค๋ธŒ์ ํŠธ์— ๋“œ๋ž˜๊ทธํ•˜์—ฌ ์ฒจ๋ถ€.

๋‹จ๊ณ„ 2. Particle System ๊ธฐ๋ณธ ๋ชจ๋“ˆ ์„ค์ • (Inspector)

์Šคํฌ๋ฆฝํŠธ์˜ SetupParticleSystem ๋ฉ”์„œ๋“œ๊ฐ€ Start์‹œ์ ์— ๋Œ€๋ถ€๋ถ„์˜ ์„ค์ •์„ ๋ฎ์–ด์“ฐ์ง€๋งŒ, ์ดˆ๊ธฐ ์„ธํŒ…์„ ๋ช…ํ™•ํžˆ ํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค์Œ ํ•ญ๋ชฉ๋“ค์„ ์ฒดํฌ.

  • Main ๋ชจ๋“ˆ
    • Start Lifetime : ์Šคํฌ๋ฆฝํŠธ ๋ณ€์ˆ˜ lifetime์œผ๋กœ ์ œ์–ด๋˜๋ฏ€๋กœ ์ž„์˜์˜ ๊ฐ’ ์„ค์ • ๊ฐ€๋Šฅ.
    • Start Size : ์Šคํฌ๋ฆฝํŠธ ๋ณ€์ˆ˜ particleSize๋กœ ์ œ์–ด.
  • Emmision ๋ชจ๋“ˆ
    • Emission over Time : ์ฒดํฌ ํ•ด์ œ (์Šคํฌ๋ฆฝํŠธ์—์„œ emission.enabled = false๋กœ ์„ค์ •ํ•˜์—ฌ ์ž๋™ ๋ฐฉ์ถœ์„ ๋”. ํŒŒํ‹ฐํด์€ ์Šคํฌ๋ฆฝํŠธ ์‹œ์ž‘ ์‹œ ํ•œ ๋ฒˆ๋งŒ ์ƒ์„ฑ๋จ).
  • Shape ๋ชจ๋“ˆ
    • Shape : ์ฒดํฌ ํ•ด์ œ (์Šคํฌ๋ฆฝํŠธ์—์„œ ์ง์ ‘ ์œ„์น˜๋ฅผ ๊ณ„์‚ฐํ•˜๋ฏ€๋กœ ๊ธฐ๋ณธ ์…ฐ์ดํ”„ ๋ฐฉ์ถœ ๊ธฐ๋Šฅ์€ ์‚ฌ์šฉ ์•ˆํ•จ).
  • Renderer ๋ชจ๋“ˆ
    • Render Mode : Billboard (์นด๋ฉ”๋ผ๋ฅผ ํ•ญ์ƒ ๋ฐ”๋ž๋ณด๋„๋ก ์„ค์ •)
    • Material : URP Lit์„ ๊ฐ€์ง„ ๋จธํ‹ฐ๋ฆฌ์–ผ์„ ํ• ๋‹น.

๋‹จ๊ณ„ 3. ๋จธํ‹ฐ๋ฆฌ์–ผ ๋ฐ ํ…์Šค์ณ ์„ค์ •

ํŒŒํ‹ฐํด์ด ํˆฌ๋ช…๋„๋ฅผ ๊ฐ€์ง€๊ณ  ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋ Œ๋”๋ง๋˜๊ธฐ ์œ„ํ•œ ์„ค์ •.

  1. ํ…์Šค์ณ ์ž„ํฌํŠธ ์„ค์ •
  • ์‚ฌ์šฉํ•  ํŒŒํ‹ฐํด ํ…์Šค์ณ(PNG)๋ฅผ Project ์ฐฝ์—์„œ ์„ ํƒ.
  • Inspector ์ฐฝ์—์„œ Texture Type์ด Default ๋˜๋Š” Sprite (2D and UI)๋กœ ์„ค์ •๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธ.
  • Alpha Source : Input Texture Alpha๋กœ ์„ค์ •.
  • Alpha Is Transparency : ์ฒดํฌ. (์ด ์˜ต์…˜์„ ์ผœ์•ผ ํ…์Šค์ณ์˜ ํˆฌ๋ช… ๋ฐฐ๊ฒฝ์ด ๋ฐ˜์˜๋จ)
  • Apply ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ ์„ค์ •์„ ์ €์žฅ.
  1. ๋จธํ‹ฐ๋ฆฌ์–ผ ์„ค์ •
  • ์ƒˆ ๋จธํ‹ฐ๋ฆฌ์–ผ์„ ์ƒ์„ฑํ•˜๊ณ  Shader๋ฅผ Universal Render Pipeline/Lit๋กœ ์„ค์ •.
  • Base Map์— ์•ž์„œ ์„ค์ •ํ•œ ํ…์Šค์ณ๋ฅผ ํ• ๋‹น.
  • Surface Type์ด Opaque๊ฐ€ ์•„๋‹Œ Transparent๋กœ ์„ค์ •๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธ.
  • ์™„์„ฑ๋œ ๋จธํ‹ฐ๋ฆฌ์–ผ์„ ํŒŒํ‹ฐํด ์‹œ์Šคํ…œ ์ปดํฌ๋„ŒํŠธ์˜ Renderer > Material ์Šฌ๋กฏ์— ํ• ๋‹น.

๋‹จ๊ณ„ 4. ์Šคํฌ๋ฆฝํŠธ ๋ณ€์ˆ˜ ์กฐ์ • (Inspector)

์˜ค๋ธŒ์ ํŠธ๋ฅผ ์„ ํƒํ•œ ์ƒํƒœ์—์„œ Inspector์˜ Generative Sphere Particles ์ปดํฌ๋„ŒํŠธ ๋ณ€์ˆ˜๋ฅผ ์กฐ์ •ํ•˜์—ฌ ์›ํ•˜๋Š” ์‹œ๊ฐ ํšจ๊ณผ๋ฅผ ์™„์„ฑ.

  • Settings

    • Max Particles: ์ƒ์„ฑํ•  ํŒŒํ‹ฐํด์˜ ์ตœ๋Œ€ ๊ฐœ์ˆ˜
    • Sphere Radius: ๊ตฌ์˜ ๋ฐ˜์ง€๋ฆ„
    • Particle Size: ๊ฐœ๋ณ„ ํŒŒํ‹ฐํด์˜ ํฌ๊ธฐ
    • Lifetime: ํŒŒํ‹ฐํด์˜ ์ˆ˜๋ช… (์Šคํฌ๋ฆฝํŠธ์—์„œ ์žฌ์ƒ์„ฑ๋˜๋ฏ€๋กœ ์‹œ๊ฐ์ ์ธ ๊ฐฑ์‹  ์ฃผ๊ธฐ์— ์˜ํ–ฅ)
  • Noise & Motion

    • Noise Strength: ๋…ธ์ด์ฆˆ์— ์˜ํ•œ ์›€์ง์ž„์˜ ์ง„ํญ (ํด์ˆ˜๋ก ๋ฉ€๋ฆฌ ์›€์ง์ž„)
    • Noise Frequency: ๋…ธ์ด์ฆˆ์˜ ์ฃผํŒŒ์ˆ˜ (ํด์ˆ˜๋ก ๋” ์ž˜๊ฒŒ, ๋น ๋ฅด๊ฒŒ ๋ณ€ํ™”)
    • Drift Speed: ํŒŒํ‹ฐํด์ด ํ๋ฅด๋Š” ์†๋„

2. ์Šคํฌ๋ฆฝํŠธ + ์ฃผ์„

using System.Numerics;
using UnityEngine;

// ์ด ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์ฒจ๋ถ€๋œ ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ์—๋Š” ๋ฐ˜๋“œ์‹œ ParticleSystem ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์žˆ์–ด์•ผ ํ•จ์„ ๋ช…์‹œ
[RequireComponent(typeof(ParticleSystem))]
public class GenerativeSphereParticles : MonoBehaviour
{
  // ==============================================================================
  // [Inspector ๋ณ€์ˆ˜ : ํŒŒํ‹ฐํด ์ƒ์„ฑ]
  // ==============================================================================
  [Header("Settings")]
  public int maxParticles = 5000;   // ํŒŒํ‹ฐํด ์ตœ๋Œ€ ๊ฐœ์ˆ˜
  public float sphereRadius = 5f;   // ํŒŒํ‹ฐํด ๋ถ„ํฌ ๊ตฌ์˜ ๋ฐ˜์ง€๋ฆ„
  public float partcleSize = 0.1f;  // ๊ฐœ๋ณ„ ํŒŒํ‹ฐํด์˜ ์‹œ์ž‘ ํฌ๊ธฐ
  public float lifetime = 5f;       // ํŒŒํ‹ฐํด ์ƒ์กด ์‹œ๊ฐ„ (์ดˆ)

  // ==============================================================================
  // [Inspector ๋ณ€์ˆ˜ : ๋…ธ์ด์ฆˆ ๋ฐ ๋ชจ์…˜]
  // ==============================================================================
  [Header("Noise & Motion")]
  public float noiseStrength = 1.8f;  // ๋…ธ์ด์ฆˆ๊ฐ€ ์œ„์น˜ ๋ณ€๋™์— ๋ฏธ์น˜๋Š” ์˜ํ–ฅ๋ ฅ (์ง„ํญ)
  public float noiseFrequency = 2.4f; // ๋…ธ์ด์ฆˆ ํ•จ์ˆ˜์˜ ์ฃผํŒŒ์ˆ˜ (์›€์ง์ž„์˜ ๋ฐ€๋„/๋นˆ๋„) 
  public float driftSpeed = 0.08f;    // ๋…ธ์ด์ฆˆ ์ƒ˜ํ”Œ๋ง ์‹œ๊ฐ„์˜ ์ฆ๊ฐ€ ์†๋„ (์›€์ง์ž„ ์†๋„)

  // ==============================================================================
  // [Private ๋ฉค๋ฒ„ ๋ณ€์ˆ˜]
  // ==============================================================================
  private ParticleSystem _ps;                   // ์บ์‹ฑ๋œ ParticleSystem ์ปดํฌ๋„ŒํŠธ ์ฐธ์กฐ
  private ParticleSystem.Particle[] _particles; // ํŒŒํ‹ฐํด ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•  ๋ฐฐ์—ด 

  // ==============================================================================
  // [Unity LifeCycle : Start]
  // ==============================================================================
  void Start()
  {
    // ์ปดํฌ๋„ŒํŠธ ์ฐธ์กฐ ๊ฐ€์ ธ์˜ค๊ธฐ
    _ps = GetComponent<ParticleSystem>();

    // ํŒŒํ‹ฐํด ์‹œ์Šคํ…œ์˜ ๊ธฐ๋ณธ ๋ชจ๋“ˆ ์„ค์ • ์ ์šฉ
    SetupParticleSystem();

    // ๋ Œ๋”๋Ÿฌ ์„ค์ • ์ ์šฉ
    SetupRenderer();

    // ํŒŒํ‹ฐํด ๋ฐ์ดํ„ฐ ์ €์žฅ์šฉ ๋ฐฐ์—ด ์ดˆ๊ธฐํ™” (์ตœ๋Œ€ ๊ฐœ์ˆ˜๋งŒํผ ํ• ๋‹น)
    _particles = new ParticleSystem.Particle[maxParticles];

    // ๊ตฌ ํ‘œ๋ฉด ์œ„์— ํŒŒํ‹ฐํด์„ ์ดˆ๊ธฐ ๋ฐฐ์น˜ํ•˜๋Š” ํ•จ์ˆ˜ ํ˜ธ์ถœ
    PlaceParticlesOnSphere();
  }

  // ==============================================================================
  // [Private Method: ParticleSystem ๋ชจ๋“ˆ ์ดˆ๊ธฐํ™”]
  // ==============================================================================
  void SetupParticleSystem()
  {
    var main = _ps.main;
    // Main ๋ชจ๋“ˆ ์†์„ฑ ์„ค์ •
    main.maxParticles = maxParticles;   // ์ตœ๋Œ€ ํŒŒํ‹ฐํด ์ˆ˜
    main.startLifetime = lifetime;      // ์ƒ์„ฑ ์‹œ ๋ถ€์—ฌ๋  ์ˆ˜๋ช…
    main.startSize = particleSize;      // ์ƒ์„ฑ ์‹œ ๋ถ€์—ฌ๋  ํฌ๊ธฐ
    main.simulationSpace = ParticleSystemSimulationSpace.World; // ์›”๋“œ ์ขŒํ‘œ๊ณ„ ๊ธฐ์ค€ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ (์˜ค๋ธŒ์ ํŠธ ์ด๋™๊ณผ ๋…๋ฆฝ์ )
    main.loop = false;                  // ์‹œ์Šคํ…œ ๋ฃจํ”„ ๋น„ํ™œ์„ฑํ™” (์ˆ˜๋™ ์ œ์–ด์šฉ)
    main.playOnAwake = false;           // ์—๋””ํ„ฐ ์‹คํ–‰ ์‹œ ์ž๋™ ์žฌ์ƒ ๋ฐฉ์ง€

    // Emission ๋ชจ๋“ˆ ์„ค์ •: ์ž๋™ ๋ฐฉ์ถœ ๋น„ํ™œ์„ฑํ™” (์ŠคํŠธ๋ฆฝํŠธ์—์„œ ์ดˆ๊ธฐ 1ํšŒ๋งŒ ๋ฐฐ์น˜ํ•˜๋ฏ€๋กœ)
    var emission = _ps.emission;
    emission.enabled = false;

    // Shape ๋ชจ๋“ˆ ์„ค์ •: ๊ธฐ๋ณธ ์…ฐ์ดํ”„ ๋ฐฉ์ถœ ๋น„ํ™œ์„ฑํ™” (์ˆ˜๋™ ์œ„์น˜ ์ง€์ • ์‚ฌ์šฉ)
    var shape = _ps.shape;
    shape.enabled = false;
  }

  // ==============================================================================
  // [Private Method: Renderer ์„ค์ •]
  // ==============================================================================
  void SetupRenderer()
  {
    var psRenderer = GetComponent<ParticleSystemRenderer>();
    // ๋ Œ๋” ๋ชจ๋“œ๋ฅผ Billboard๋กœ ์„ค์ •: ํŒŒํ‹ฐํด์ด ํ•ญ์ƒ ์นด๋ฉ”๋ผ๋ฅผ ๋ฐ”๋ผ๋ณด๊ฒŒ ํ•จ (2D ์Šคํ”„๋ผ์ดํŠธ์ฒ˜๋Ÿผ ๋ณด์ž„)
    psRenderer.renderMode = ParticleSystemRenderMode.Billboard;

    // ์ฐธ๊ณ : Material์€ Inspector์—์„œ ์ง์ ‘ ํ• ๋‹น
  }

  // ==============================================================================
  // [Private Method: ๊ตฌ ํ‘œ๋ฉด ์œ„ ํŒŒํ‹ฐํด ์ดˆ๊ธฐ ๋ฐฐ์น˜]
  // ==============================================================================
  void PlaceParticlesOnSphere()
  {
    // ์ตœ๋Œ€ ํŒŒํ‹ฐํด ๊ฐœ์ˆ˜๋งŒํผ ๋ฐ˜๋ณต
    for (int i = 0; i < maxParticles; i++)
    {
      // Random.outUnitSphere: ๋ฐ˜์ง€๋ฆ„ 1์ธ ๊ตฌ ํ‘œ๋ฉด์˜ ๋žœ๋คํ•œ ๋ฐฉํ–ฅ ๋ฒกํ„ฐ๋ฅผ ๋ฐ˜ํ™˜
      // ์—ฌ๊ธฐ์— sphereRadius๋ฅผ ๊ณฑํ•˜์—ฌ ์‹ค์ œ ํฌ๊ธฐ์˜ ๊ตฌ ํ‘œ๋ฉด ์ขŒํ‘œ๋กœ ๋ณ€ํ™˜
      _particles[i].position = Random.onUnitSphere * sphereRadius;

      // ํŒŒํ‹ฐํด์˜ ์ˆ˜๋ช… ์†์„ฑ ์„ค์ •
      _particles[i].startLifetime = lifetime;
      _particles[i].remainingLifetime = lifetime; // ํ˜„์žฌ ๋‚จ์€ ์ˆ˜๋ช…๋„ ์ตœ๋Œ€ ์ˆ˜๋ช…์œผ๋กœ ์ดˆ๊ธฐํ™”

      // ํŒŒํ‹ฐํด ํฌ๊ธฐ ์„ค์ •
      _particles[i].startSize = particleSize;
    }
    // ์„ค์ •๋œ ํŒŒํ‹ฐํด ๋ฐ์ดํ„ฐ ๋ฐฐ์—ด์„ ์‹ค์ œ ParticleSystem์— ์ ์šฉ (๊ฐœ์ˆ˜ ์ง€์ •)
    _ps.SetParticles(_particles, maxParticles);
  }


  // ==============================================================================
  // [Unity LifeCycle: LateUpdate]
  // ==============================================================================
  void LateUpdate()
  {
    // ํ˜„์žฌ ํ™œ์„ฑํ™”๋œ ํŒŒํ‹ฐํด์˜ ๊ฐœ์ˆ˜๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ , ๋ฐฐ์—ด์— ๋ฐ์ดํ„ฐ๋ฅผ ์ฑ„์›€
    // ์ฐธ๊ณ : ์ด ์‹œ์Šคํ…œ์€ ํŒŒํ‹ฐํด์„ ์†Œ๋ฉธ์‹œํ‚ค์น˜ ์•Š๊ณ  ์žฌํ™œ์šฉํ•˜๋ฏ€๋กœ ํ†ต์ƒใ…ˆ์ ์œผ๋กœ count == maxParticles
    int count = _ps.GetParticles(_particles);
    float time = Time.time;   // ํ˜„์žฌ ๊ฒŒ์ž„ ์‹œ๊ฐ„ ์ €์ • (๋งค ํ”„๋ ˆ์ž„ ํ˜ธ์ถœ ๋ฐฉ์ง€์šฉ)

    // ํ™œ์„ฑํ™”๋œ ๋ชจ๋“  ํŒŒํ‹ฐํด์— ๋Œ€ํ•ด ์ฒ˜๋ฆฌ
    for (int i = 0; i < count; i++)
    {
      // --------------------------------------------------------------------------
      // [Perlin Noise ๋ฅผ ์ด์šฉํ•œ ์œ ๊ธฐ์  ์˜คํ”„์…‹ ๊ณ„์‚ฐ]
      // --------------------------------------------------------------------------
      // Mathf.PerlinNoise(x,y): 0.0 ~ 1.0 ์‚ฌ์ด์˜ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋…ธ์ด์ฆˆ ํ•จ์ˆ˜
      // 1. ์ธ๋ฑ์Šค(i)์— ๊ณ ์œ ํ•œ ์†Œ์ˆ˜(0.3171f ๋“ฑ)๋ฅผ ๊ณฑํ•˜์—ฌ ๊ฐ ํŒŒํ‹ฐํด๋งˆ๋‹ค ๋‹ค๋ฅธ ๋…ธ์ด์ฆˆ ํŒจํ„ด ์ƒ์„ฑ
      // 2. time * driftSpeed ๋ฅผ ์ž…๋ ฅํ•˜์—ฌ ์‹œ๊ฐ„์— ๋”ฐ๋ผ ๋…ธ์ด์ฆˆ ๊ฐ’์ด ๋ณ€ํ•˜๋„๋ก (์• ๋‹ˆ๋ฉ”์ด์…˜ ํšจ๊ณผ)
      // 3. ๊ฒฐ๊ณผ๊ฐ’์—์„œ 0.5๋ฅผ ๋นผ์„œ -0.5 ~ 0.5 ๋ฒ”์œ„์˜ ์ค‘์‹ฌ๊ฐ’์„ ๊ฐ–์ง„ ์˜คํ”„์…‹์œผ๋กœ ๋ณ€ํ™˜

      float nX = MathF.PerlinNoise(i * 0.3171f, time * driftSpeed) - 0.5f;
      float nY = MathF.PerlinNoise(i * 0.6457f, time * driftSpeed) - 0.5f;
      float nZ = MathF.PerlinNoise(i * 0.9133f, time * driftSpeed) - 0.5f;

      // ๊ณ„์‚ฐ๋œ ๋…ธ์ด์ฆˆ ๊ฐ’์„ ๋ฒกํ„ฐ๋กœ ๊ตฌ์„ฑํ•˜๊ณ , Strength๋ฅผ ๊ณฑํ•˜์—ฌ ์ด๋™ ๊ฑฐ๋ฆฌ๋ฅผ ์กฐ์ ˆ
      Vector3 noiseOffset = new Vector3(nX, nY, nZ) * noiseStrength;

      // --------------------------------------------------------------------------
      // [๊ตฌ ํ‘œ๋ฉด ์œ„์— ํŒŒํ‹ฐํด์„ ๊ตฌ์†ํ•˜๋Š” ๋กœ์ง]
      // --------------------------------------------------------------------------
      // 1. ํ˜„์žฌ ํŒŒํ‹ฐํด ์œ„์น˜๋ฅผ ์ •๊ทœํ™” (.normalized): ์›์ ์—์„œ์˜ ๋ฐฉํ–ฅ ๋ฒกํ„ฐ๋งŒ ์ถ”์ถœ (๊ธธ์ด = 1)
      // 2. ์—ฌ๊ธฐ์— ๋…ธ์ด์ฆˆ ์˜คํ”„์…‹์„ ๋”ํ•จ: ๋ฐฉํ–ฅ์„ ์‚ด์ง ๋น„ํ‹€์–ด ์›€์ง์ž„์„ ๋ถ€์—ฌ
      // 3. ๋‹ค์‹œ ์ •๊ทœํ™” (.normalized): ๋น„ํ‹€์–ด์ง„ ๋ฒกํ„ฐ๋ฅผ ๋‹ค์‹œ ๊ธธ์ด 1์˜ ๋‹จ์œ„ ๋ฒกํ„ฐ๋กœ ๋งŒ๋“ฆ (ํ‘œ๋ฉด ์žฌ๊ณ ์ •)
      // 4. sphereRadius๋ฅผ ๊ณฑํ•จ : ์‹ค์ œ ๊ตฌ์˜ ํฌ๊ธฐ๋กœ ์Šค์ผ€์ผ๋ง
      // ๊ฒฐ๊ณผ: ํŒŒํ‹ฐํด์€ ๊ตฌ์˜ ์ค‘์‹ฌ์—์„œ ์ผ์ •ํ•œ ๊ฑฐ๋ฆฌ(๋ฐ˜์ง€๋ฆ„)๋ฅผ ์œ ์ง€ํ•˜๋ฉฐ ํ‘œ๋ฉด ์œ„๋ฅผ ๋ฏธ๋„๋Ÿฌ์ง€๋“ฏ ์ด๋™
      Vector3 nextPos = (_particles[i].position.nomalized + noiseOffset).normalized * sphereRadius;

      // ๊ณ„์‚ฐ๋œ ์ƒˆ ์œ„์น˜๋ฅผ ํŒŒํ‹ฐํด์— ์ ์šฉ
      _particles[i].position = nextPos;

      // ๋‚จ์€ ์ˆ˜๋ช…์„ ๊ฐ•์ œ๋กœ ์ตœ๋Œ€ ์ˆ˜๋ช…์œผ๋กœ ์žฌ์‹œ์ž‘
      // ํŒŒํ‹ฐํด์ด ์†Œ๋ฉธํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€, ๊ณ„์† ์›€์ง์ด๋„๋ก
      _particles[i].remainingLifetime = lifetime;
    }
    
    // ์ˆ˜์ •๋œ ํŒŒํ‹ฐํด ๋ฐ์ดํ„ฐ ๋ฐฐ์—ด์„ ParticleSystem์— ๋‹ค์‹œ ์—…๋กœ๋“œํ•˜์—ฌ ํ™”๋ฉด์— ๋ฐ˜์˜
    _ps.SetParticles(_particles, count);
  }
}

profile
Coding Art with Blender / oF / Processing / p5.js / nannou

0๊ฐœ์˜ ๋Œ“๊ธ€