🫧Art_004 Radial Energy Field [GPU Instancing]

BamgasiJM·2026년 3월 13일

Unity GenArt

목록 보기
13/41
post-thumbnail

📄Art_004_Radial_Energy_Field_GPU.cs

using UnityEngine;
using System.Collections.Generic;

[ExecuteAlways]
public class RadialEnergyField_GPU : MonoBehaviour
{
    [Header("Structure")]
    public int ringCount = 30;
    public int baseSegments = 8;
    public float ringSpacing = 1.1f;

    [Header("Wave")]
    public float waveHeight = 2.5f;
    public float waveSpeed = 1.4f;
    public float waveFrequency = 1.3f;

    [Header("Swirl")]
    public float swirlStrength = 0.6f;
    public float radialPulse = 0.8f;

    [Header("Scale")]
    public float scaleMin = 0.2f;
    public float scaleMax = 1.0f;

    [Header("Color Palette")]
    [Range(0,1)] public float hueBase = 0.02f;
    [Range(0,1)] public float hueRange = 0.55f;

    public float emissionIntensity = 4f;

    public Mesh sphereMesh;
    public Material instancedMaterial;

    struct Particle
    {
        public float radius;
        public float angle;
    }

    List<Particle> particles = new List<Particle>();

    Matrix4x4[] matrices;
    Vector4[] colors;

    MaterialPropertyBlock block;

    const int BATCH_SIZE = 1023;

    bool generated = false;

    void OnEnable()
    {
        EnsureResources();
        Generate();
    }

    void EnsureResources()
    {
        if (sphereMesh == null)
        {
            GameObject g = GameObject.CreatePrimitive(PrimitiveType.Sphere);
            sphereMesh = g.GetComponent<MeshFilter>().sharedMesh;
            DestroyImmediate(g);
        }

        if (instancedMaterial == null)
        {
            Shader shader =
                Shader.Find("Universal Render Pipeline/Lit") ??
                Shader.Find("Standard");

            instancedMaterial = new Material(shader);
            instancedMaterial.enableInstancing = true;
            instancedMaterial.EnableKeyword("_EMISSION");
        }

        if (block == null)
            block = new MaterialPropertyBlock();
    }

    void Generate()
    {
        particles.Clear();

        particles.Add(new Particle
        {
            radius = 0,
            angle = 0
        });

        for (int ring = 1; ring <= ringCount; ring++)
        {
            float radius = ring * ringSpacing;
            int segments = baseSegments * ring;

            for (int s = 0; s < segments; s++)
            {
                float angle = (float)s / segments * Mathf.PI * 2f;

                particles.Add(new Particle
                {
                    radius = radius,
                    angle = angle
                });
            }
        }

        matrices = new Matrix4x4[particles.Count];
        colors = new Vector4[particles.Count];

        generated = true;

        Animate(0f);
        RenderInstances();
    }

    void Update()
    {
        if (!generated)
            return;

        if (!Application.isPlaying)
        {
            Animate(0f);
            RenderInstances();
            return;
        }

        float t = Time.time * waveSpeed;

        Animate(t);
        RenderInstances();
    }

    void Animate(float t)
    {
        for (int i = 0; i < particles.Count; i++)
        {
            var p = particles[i];

            float wave =
                Mathf.Sin(p.radius * waveFrequency - t) * waveHeight;

            float normalized =
                (wave / waveHeight + 1f) * 0.5f;

            float swirl =
                Mathf.Sin(t + p.radius) * swirlStrength;

            float angle =
                p.angle + swirl;

            float r =
                p.radius +
                Mathf.Sin(t + p.radius) * radialPulse;

            Vector3 pos = new Vector3
            (
                Mathf.Cos(angle) * r,
                wave,
                Mathf.Sin(angle) * r
            );

            float scale =
                Mathf.Lerp(scaleMin, scaleMax, normalized);

            matrices[i] =
                Matrix4x4.TRS(pos, Quaternion.identity, Vector3.one * scale);

            float hue =
                (hueBase + normalized * hueRange) % 1f;

            Color col =
                Color.HSVToRGB(hue,1,1);

            colors[i] = col;
        }
    }

    void RenderInstances()
    {
        int total = particles.Count;
        int index = 0;

        while (total > 0)
        {
            int batch = Mathf.Min(BATCH_SIZE, total);

            Matrix4x4[] batchMatrices = new Matrix4x4[batch];
            Vector4[] batchColors = new Vector4[batch];

            System.Array.Copy(matrices, index, batchMatrices, 0, batch);
            System.Array.Copy(colors, index, batchColors, 0, batch);

            block.Clear();

            block.SetVectorArray("_BaseColor", batchColors);
            block.SetVectorArray("_EmissionColor", batchColors);

            Graphics.DrawMeshInstanced(
                sphereMesh,
                0,
                instancedMaterial,
                batchMatrices,
                batch,
                block
            );

            index += batch;
            total -= batch;
        }
    }
}

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

0개의 댓글