๐ŸซงArt_005 Radial Pulse

BamgasiJMยท2026๋…„ 3์›” 13์ผ

Unity GenArt

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

GameObject์— ๋ถ™์—ฌ์„œ ์‚ฌ์šฉ

๐Ÿ“„Art_005_Radial_Pulse.cs

using UnityEngine;
using System.Collections.Generic;

public class Art_RadialPulse : MonoBehaviour
{
	[Header("๊ทธ๋ฆฌ๋“œ ๊ตฌ์กฐ (๋ณ€๊ฒฝ ์‹œ ์˜ค๋ธŒ์ ํŠธ ์žฌ์ƒ์„ฑ)")]
	public int ringCount = 15;
	public int baseSegments = 6;
	public float ringSpacing = 1.2f;

	[Header("ํŒŒ๋™ ์„ค์ • (์‹ค์‹œ๊ฐ„ ๋ฐ˜์˜)")]
	public float waveHeight = 2.2f;
	public float waveSpeed = 1.2f;
	public float waveFrequency = 1.2f;

	[Header("ํฌ๊ธฐ ์„ค์ • (์‹ค์‹œ๊ฐ„ ๋ฐ˜์˜)")]
	public float scaleMin = 0.25f;
	public float scaleMax = 0.85f;

	[Header("์ƒ‰์ƒ ์„ค์ • (์‹ค์‹œ๊ฐ„ ๋ฐ˜์˜)")]
	[Range(0f, 1f)] public float hueBase = 0.55f;
	[Range(0f, 1f)] public float hueRange = 0.35f;
	public float emissionIntensity = 1.2f;

	[Header("์žฌ์งˆ ์„ค์ •")]
	public Material baseMaterial;

	// ---------------------------------------------------
	// ํ๋ธŒ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ์ฒด
	// ---------------------------------------------------
	struct CubeData
	{
		public Transform tr;
		public Material mat;
		public float radius;
		public Vector3 basePos;
	}

	List<CubeData> _cubes = new List<CubeData>();

	// ---------------------------------------------------
	// Unity ์ด๋ฒคํŠธ
	// ---------------------------------------------------

	void OnEnable()
	{
		// baseMaterial ์ด ์—†์œผ๋ฉด URP ๊ธฐ๋ณธ ๋จธํ‹ฐ๋ฆฌ์–ผ ์ž๋™ ์ƒ์„ฑ
		if (baseMaterial == null)
			baseMaterial = CreateURPMaterial();
		Generate();
	}

	void Update()
	{
		// ๊ฒŒ์ž„ ์‹คํ–‰ ์ค‘ ํ•ญ์ƒ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ ์šฉ (์—๋””ํ„ฐ ์ฒดํฌ ์ œ๊ฑฐ)
		ApplyAnimation(Time.time * waveSpeed);
	}

	void OnDisable()
	{
		Clear();  // ์ปดํฌ๋„ŒํŠธ ๋น„ํ™œ์„ฑํ™” ์‹œ ๋ฉ”๋ชจ๋ฆฌ ์ •๋ฆฌ
	}

	// ---------------------------------------------------
	// ๊ทธ๋ฆฌ๋“œ ์ƒ์„ฑ
	// ---------------------------------------------------

	void Generate()
	{
		Clear();
		SpawnCube(Vector3.zero, 0f); // ์ค‘์‹ฌ ํ๋ธŒ ์ƒ์„ฑ

		// ๋™์‹ฌ์› ๊ทธ๋ฆฌ๋“œ ์ƒ์„ฑ
		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;
				Vector3 pos = new Vector3(
						Mathf.Cos(angle) * radius,
						0f,
						Mathf.Sin(angle) * radius
				);
				SpawnCube(pos, radius);
			}
		}
		ApplyAnimation(0f);
	}

	void SpawnCube(Vector3 pos, float radius)
	{
		GameObject go = GameObject.CreatePrimitive(PrimitiveType.Cube);
		go.transform.SetParent(transform);
		go.transform.localPosition = pos;
		go.transform.localScale = Vector3.one * scaleMin;

		// ๋จธํ‹ฐ๋ฆฌ์–ผ ์ธ์Šคํ„ด์Šคํ™” ๋ฐ ์ด๋ฏธ์‹œ๋ธŒ ์„ค์ •
		Material mat = Instantiate(baseMaterial);
		mat.EnableKeyword("_EMISSION");
		mat.globalIlluminationFlags = MaterialGlobalIlluminationFlags.RealtimeEmissive;

		go.GetComponent<Renderer>().material = mat;

		_cubes.Add(new CubeData
		{
			tr = go.transform,
			mat = mat,
			radius = radius,
			basePos = pos
		});
	}

	void Clear()
	{
		// ๋Ÿฐํƒ€์ž„ ์•ˆ์ „ํ•œ ๋ฐฉ์‹์œผ๋กœ ์˜ค๋ธŒ์ ํŠธ ๋ฐ ๋จธํ‹ฐ๋ฆฌ์–ผ ์ •๋ฆฌ
		foreach (var cube in _cubes)
		{
			if (cube.mat != null)
				Destroy(cube.mat);
			if (cube.tr != null)
				Destroy(cube.tr.gameObject);
		}
		_cubes.Clear();
	}

	// ---------------------------------------------------
	// ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ ์šฉ
	// ---------------------------------------------------

	void ApplyAnimation(float t)
	{
		for (int i = 0; i < _cubes.Count; i++)
		{
			CubeData c = _cubes[i];
			if (c.tr == null || c.mat == null) continue;

			// ํŒŒ๋™ ๊ณ„์‚ฐ
			float wave = Mathf.Sin(c.radius * waveFrequency - t) * waveHeight;
			float normalized = (wave / waveHeight + 1f) * 0.5f;

			// ์œ„์น˜ ์—…๋ฐ์ดํŠธ (Y์ถ•์œผ๋กœ ํŒŒ๋™)
			Vector3 p = c.basePos;
			p.y = wave;
			c.tr.localPosition = p;

			// ์Šค์ผ€์ผ ์—…๋ฐ์ดํŠธ
			c.tr.localScale = Vector3.one * Mathf.Lerp(scaleMin, scaleMax, normalized);

			// ์ƒ‰์ƒ ๊ณ„์‚ฐ (HSV ๊ธฐ๋ฐ˜ ๊ทธ๋ผ๋ฐ์ด์…˜)
			float hue = (hueBase + normalized * hueRange) % 1f;
			Color albedo = Color.HSVToRGB(hue, 0.7f, 1f);
			Color emission = Color.HSVToRGB(hue, 1f, normalized) * emissionIntensity;

			// URP ์ „์šฉ ์…ฐ์ด๋” ํ”„๋กœํผํ‹ฐ ์ ์šฉ
			c.mat.SetColor("_BaseColor", albedo);
			c.mat.SetColor("_EmissionColor", emission);
		}
	}

	// ---------------------------------------------------
	// ์œ ํ‹ธ๋ฆฌํ‹ฐ: URP ์ „์šฉ ๋จธํ‹ฐ๋ฆฌ์–ผ ์ƒ์„ฑ
	// ---------------------------------------------------

	Material CreateURPMaterial()
	{
		Shader urpShader = Shader.Find("Universal Render Pipeline/Lit");
		if (urpShader == null)
		{
			Debug.LogWarning("[Art_RadialPulse] URP ์…ฐ์ด๋”๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. Inspector ์—์„œ baseMaterial ์„ ์ง์ ‘ ํ• ๋‹นํ•ด์ฃผ์„ธ์š”.");
			return new Material(Shader.Find("Diffuse"));
		}

		Material mat = new Material(urpShader);
		mat.EnableKeyword("_EMISSION");
		mat.globalIlluminationFlags = MaterialGlobalIlluminationFlags.RealtimeEmissive;
		return mat;
	}
}

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

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