
📄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;
}
}
}