🫧Art_016 Gaussian Cluster Rotation

BamgasiJM·2026년 3월 27일

Unity GenArt

목록 보기
27/41
post-thumbnail

📒 GaussianClusterRotation.cs

using UnityEngine;
using UnityEngine.Rendering;

#if UNITY_EDITOR
using UnityEditor;
#endif

[ExecuteAlways]
public class GaussianClusterRotation : MonoBehaviour
{
    // -----------------------------------------------------------
    // Structure
    // -----------------------------------------------------------

    [Header("Structure")]
    [Range(100, 20000)] public int count = 5000;
    [Range(0.1f, 10f)] public float radius = 5f;
    [Range(0.1f, 5f)] public float sigma = 1.5f;

    // -----------------------------------------------------------
    // Rotation
    // -----------------------------------------------------------

    [Header("Rotation")]
    public float minSpeed = 0.2f;
    public float maxSpeed = 2.5f;

    [Tooltip("중심부 속도 배율")]
    [Range(1f, 5f)] public float centerSpeedBoost = 2.5f;

    // -----------------------------------------------------------
    // Size
    // -----------------------------------------------------------

    [Header("Size")]
    public float minSize = 0.03f;
    public float maxSize = 0.08f;

    // -----------------------------------------------------------
    // Color (HSV)
    // -----------------------------------------------------------

    [Header("Color (HSV Spectrum)")]

    [Tooltip("느린 속도 Hue (0 = Red, 0.15 = Yellow 등)")]
    [Range(0f, 1f)] public float hueSlow = 0.0f;   // Red

    [Tooltip("빠른 속도 Hue")]
    [Range(0f, 1f)] public float hueFast = 0.12f;  // Yellow/Orange

    [Range(0f, 1f)] public float saturation = 0.9f;

    [Tooltip("최소 밝기")]
    [Range(0f, 1f)] public float valueMin = 0.6f;

    [Tooltip("최대 밝기")]
    [Range(0f, 2f)] public float valueMax = 1.4f;

    [Tooltip("색 대비 (지각 보정)")]
    [Range(0.5f, 5f)] public float contrastPower = 2.2f;

    // -----------------------------------------------------------
    // 내부 데이터
    // -----------------------------------------------------------

    struct Particle
    {
        public Vector3 basePos;
        public float radius;
        public float angle;
        public float speed;
        public float size;
        public float speed01;
    }

    Particle[] _p;

    Mesh _mesh;
    Material _mat;
    MaterialPropertyBlock _mpb;

    const int BATCH = 1023;
    readonly Matrix4x4[] _mBuf = new Matrix4x4[BATCH];
    readonly Vector4[] _cBuf = new Vector4[BATCH];

#if UNITY_EDITOR
  bool _queued;
#endif

    // -----------------------------------------------------------
    // Unity
    // -----------------------------------------------------------

    void OnEnable()
    {
        Init();
        if (_p == null || _p.Length == 0)
            Generate();
    }

    void Update()
    {
        if (_mesh == null || _mat == null || _p == null) return;

#if UNITY_EDITOR
    if (!Application.isPlaying)
    {
      Render(0f);
      return;
    }
#endif

        Render(Time.time);
    }

#if UNITY_EDITOR
  void OnValidate()
  {
    Init();

    if (_queued) return;
    _queued = true;

    EditorApplication.delayCall += () =>
    {
      _queued = false;
      if (this == null) return;
      Generate();
    };
  }
#endif

    // -----------------------------------------------------------
    // Generate
    // -----------------------------------------------------------

    void Generate()
    {
        _p = new Particle[count];

        for (int i = 0; i < count; i++)
        {
            Vector3 dir = Random.onUnitSphere;

            // Gaussian (Box-Muller)
            float g = Mathf.Sqrt(-2f * Mathf.Log(Mathf.Max(0.0001f, Random.value)))
                      * Mathf.Cos(Random.value * Mathf.PI * 2f);

            float r = Mathf.Min(Mathf.Abs(g) * sigma, 1f) * radius;
            float radial01 = r / radius;

            float speed = Random.Range(minSpeed, maxSpeed);

            // ✅ 중심부 빠르게
            float centerBoost = Mathf.Lerp(centerSpeedBoost, 1f, radial01);
            speed *= centerBoost;

            // ✅ 정규화 (min/max 기준 유지)
            float speed01 = Mathf.InverseLerp(minSpeed, maxSpeed, speed);

            // ✅ 대비 강화
            speed01 = Mathf.Pow(speed01, contrastPower);

            _p[i] = new Particle
            {
                basePos = dir * r,
                radius = r,
                angle = Random.value * Mathf.PI * 2f,
                speed = speed,
                size = Random.Range(minSize, maxSize),
                speed01 = speed01
            };
        }
    }

    // -----------------------------------------------------------
    // Render
    // -----------------------------------------------------------

    void Render(float t)
    {
        int total = _p.Length;
        int offset = 0;

        while (offset < total)
        {
            int n = Mathf.Min(BATCH, total - offset);

            for (int i = 0; i < n; i++)
            {
                ref Particle p = ref _p[offset + i];

                float a = p.angle + t * p.speed;

                float cos = Mathf.Cos(a);
                float sin = Mathf.Sin(a);

                Vector3 pos = new Vector3(
                  p.basePos.x * cos - p.basePos.z * sin,
                  p.basePos.y,
                  p.basePos.x * sin + p.basePos.z * cos
                );

                _mBuf[i] = Matrix4x4.TRS(pos, Quaternion.identity, Vector3.one * p.size);

                // ✅ HSV 기반 색상
                float hue = Mathf.Lerp(hueSlow, hueFast, p.speed01);
                float value = Mathf.Lerp(valueMin, valueMax, p.speed01);

                Color c = Color.HSVToRGB(hue, saturation, value);

                // ✅ 추가 밝기 보정 (요청한 부분)
                c *= Mathf.Lerp(0.6f, 1.4f, p.speed01);

                _cBuf[i] = new Vector4(c.r, c.g, c.b, 1f);
            }

            _mpb.Clear();
            _mpb.SetVectorArray("_BaseColor", _cBuf);

            Graphics.DrawMeshInstanced(_mesh, 0, _mat, _mBuf, n, _mpb);

            offset += n;
        }
    }

    // -----------------------------------------------------------
    // Resources
    // -----------------------------------------------------------

    void Init()
    {
        if (_mesh == null)
            _mesh = Resources.GetBuiltinResource<Mesh>("Sphere.fbx");

        if (_mat == null)
        {
            var sh = Shader.Find("Universal Render Pipeline/Unlit");
            if (sh == null)
            {
                Debug.LogError("URP Unlit shader not found");
                return;
            }

            _mat = new Material(sh);
            _mat.enableInstancing = true;
        }

        _mpb ??= new MaterialPropertyBlock();
    }
}

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

0개의 댓글