


Compute Shader๋ก ๋ง๋ ๊ฒฐ๊ณผ๋ฅผ ์ค๋ธ์ ํธ์ ๋จธํฐ๋ฆฌ์ผ์ ๊ณต๊ธํด ์๊ฐ์ ํจ๊ณผ๋ฅผ ์ฃผ๋ ๋ฐฉ์
HLSL, .compute ํ์ผ)์
๋๋ค.ComputeBuffer, Dispatch()๋ก ์คํ์ ์ ์ดํฉ๋๋ค.GameObject ์์ฑComputePreview.cs (์ปจํธ๋กค๋ฌ ์ญํ ) ์์ฑํ ๋ค์์ GameObject์ ๋ถ์ฐฉGameObject์ Inspector์์ ์ฐธ์กฐ ์ค์ NoiseCompute.compute์์ GPU ์ฐ์ฐ(๋
ธ์ด์ฆ ์์ฑ)์ ์ํComputePreview.cs๊ฐ ์ปดํจํธ ์
ฐ์ด๋๋ฅผ ์คํ(Dispatch)ํ๊ณ ๊ฒฐ๊ณผ RenderTexture๋ฅผ ๋ฐ์[ExecuteAlways]๋ก ์๋ํฐ์์๋ ์ฆ์ ๋ฏธ๋ฆฌ๋ณด๊ธฐ ๊ฐ๋ฅMaterialPropertyBlock์ผ๋ก ์ ์ฉํด์ ๋จธํฐ๋ฆฌ์ผ ์์
์ค์ผ/์ ํ ๋ฌธ์ ๋ฐฉ์ง// ์ด ํ์ผ์์ ์ฌ์ฉํ ์ปค๋(์ง์
ํจ์) ์ด๋ฆ ์ ์ธ
#pragma kernel CSMain
// Compute Shader๊ฐ ์ต์ข
๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋กํ ์ถ๋ ฅ ํ
์ค์ฒ
// RWTexture2D: ์ฝ๊ธฐ/์ฐ๊ธฐ ๊ฐ๋ฅ(์ฌ๊ธฐ์๋ ์ฐ๊ธฐ ์ค์ฌ)
RWTexture2D<float4> Result;
// C#์์ SetInt/SetFloat๋ก ์ ๋ฌ๋ฐ๋ ํ๋ผ๋ฏธํฐ๋ค
uint _Width; // ์ถ๋ ฅ ํ
์ค์ฒ ๊ฐ๋ก ํด์๋
uint _Height; // ์ถ๋ ฅ ํ
์ค์ฒ ์ธ๋ก ํด์๋
float _TimeValue; // ์๊ฐ ๊ฐ(ํ๋ ์ด ๋ชจ๋์์๋ Time.time, ์๋ํฐ๋ ๊ณ ์ ๊ฐ ๊ฐ๋ฅ)
float _Scale; // ๋
ธ์ด์ฆ ํ๋/์ถ์ ์ ๋
float _Speed; // ์๊ฐ์ ๋ฐ๋ฅธ ํ๋ฆ ์๋
float4 _ColorA; // C#์์ ์ ๋ฌ๋ฐ๋ ๋ ์ (RGB๋ง ์ฌ์ฉ, A๋ ๋ฌด์ ๊ฐ๋ฅ)
float4 _ColorB;
// 2D ์ขํ -> 0~1 ๋๋ค๊ฐ์ฒ๋ผ ๋ณด์ด๋ ํด์ ํจ์
// ์์ ํ ๋๋ค์ ์๋๊ณ , ์ขํ ๊ธฐ๋ฐ ์์ฌ๋์ ์์ฑ๊ธฐ
float hash21(float2 p)
{
p = frac(p * float2(123.34, 456.21));
p += dot(p, p + 45.32);
return frac(p.x * p.y);
}
// value noise ์คํ์ผ์ 2D ๋
ธ์ด์ฆ ํจ์
// uv ์์น์์ ์ฃผ๋ณ 4๊ฐ ๊ทธ๋ฆฌ๋ ๊ฐ(a,b,c,d)์ ๋ณด๊ฐํด ๋ถ๋๋ฌ์ด ๊ฐ ์์ฑ
float noise2(float2 uv)
{
// ํ์ฌ uv๊ฐ ์ํ ์ ์ ๊ฒฉ์ ์ขํ
float2 i = floor(uv);
// ๊ฒฉ์ ๋ด ๋ก์ปฌ ์ขํ(0~1)
float2 f = frac(uv);
// ๊ฒฉ์ 4๊ฐ ๊ผญ์ง์ ์์ ํด์๊ฐ ์ํ
float a = hash21(i);
float b = hash21(i + float2(1.0, 0.0));
float c = hash21(i + float2(0.0, 1.0));
float d = hash21(i + float2(1.0, 1.0));
// ๋ณด๊ฐ ๊ณก์ (๋ถ๋๋ฌ์ด ์คํ
): f*f*(3-2f)
float2 u = f * f * (3.0 - 2.0 * f);
// x๋ฐฉํฅ ๋ณด๊ฐ ํ y๋ฐฉํฅ ๋ณด๊ฐ
return lerp(lerp(a, b, u.x), lerp(c, d, u.x), u.y);
}
// ์ค๋ ๋ ๊ทธ๋ฃน ํฌ๊ธฐ(ํ ๊ทธ๋ฃน์ 8x8 ์ค๋ ๋)
// C# Dispatch์์ (ceil(width/8), ceil(height/8), 1)๋ก ๋ง์ถฐ ์คํ
[numthreads(8, 8, 1)]
void CSMain(uint3 id : SV_DispatchThreadID)
{
// id.x, id.y๊ฐ ํ
์ค์ฒ ๋ฒ์๋ฅผ ๋์ผ๋ฉด ์ฆ์ ์ข
๋ฃ
// (๊ฐ์ฅ์๋ฆฌ ๊ทธ๋ฃน์์ ์ด๊ณผ ์ค๋ ๋๊ฐ ์๊ธธ ์ ์์ด์ ํ์)
if (id.x >= _Width || id.y >= _Height) return;
// ํ์ฌ ํฝ์
id๋ฅผ 0~1 UV๋ก ์ ๊ทํ
// +0.5๋ ํฝ์
์ค์ฌ ์ํ๋ง ๋๋์ ์ฃผ๊ธฐ ์ํ ์คํ์
float2 uv = float2((id.x + 0.5) / (float)_Width, (id.y + 0.5) / (float)_Height);
// ์๊ฐ์ ๋ฐ๋ผ x์ถ ๋ฐฉํฅ์ผ๋ก ์ด๋ํ๋ ๋
ธ์ด์ฆ
// _Scale: ํจํด ํฌ๊ธฐ, _Speed: ์์ง์ ์๋
float n = noise2(uv * _Scale + float2(_TimeValue * _Speed, 0.0));
// ๋
ธ์ด์ฆ ํจํด์ ์ฐ์ด๋ ๋ ์์ n์ผ๋ก ๋ณด๊ฐ
float3 col = lerp(_ColorA.rgb, _ColorB.rgb, n);
// ๊ฒฐ๊ณผ๋ฅผ ์ถ๋ ฅ ํ
์ค์ฒ์ ํ์ฌ ํฝ์
์ ๊ธฐ๋ก
Result[int2(id.xy)] = float4(col, 1.0);
}
using UnityEngine;
// ================================================================
// ComputePreview
// [ExecuteAlways] ๋ก ์๋ํฐ/ํ๋ ์ด ๋ชจ๋ ๋ชจ๋์์ ์คํ๋ฉ๋๋ค.
// ์ปดํจํธ ์
ฐ์ด๋๋ก ํ๋ก์์ ๋ด ๋
ธ์ด์ฆ ํ
์ค์ฒ๋ฅผ ์์ฑํ๊ณ ,
// MaterialPropertyBlock์ ํตํด ํ๊ฒ ๋ ๋๋ฌ์ ์ค์๊ฐ ๋ฐ์ํฉ๋๋ค.
// ================================================================
[ExecuteAlways] // ์๋ํฐ์ ํ๋ ์ด ๋ชจ๋ ๋ชจ๋์์ ์คํ๋๋๋ก ์ค์
public class ComputePreview : MonoBehaviour
{
// ----------------------------------------------------------------
// ์ธ์คํํฐ ๋
ธ์ถ ํ๋
// ----------------------------------------------------------------
[Header("References")]
[SerializeField] ComputeShader compute; // ๋
ธ์ด์ฆ ์์ฑ์ฉ ์ปดํจํธ ์
ฐ์ด๋
[SerializeField] Renderer targetRenderer; // ํ
์ค์ฒ๋ฅผ ์
ํ ๋์ ๋ ๋๋ฌ
[Header("Texture")]
[SerializeField, Range(32, 2048)] int width = 512; // ๋ ๋ ํ
์ค์ฒ ๊ฐ๋ก ํด์๋
[SerializeField, Range(32, 2048)] int height = 512; // ๋ ๋ ํ
์ค์ฒ ์ธ๋ก ํด์๋
[Header("Noise Params")]
[SerializeField, Min(0.01f)] float scale = 8f; // ๋
ธ์ด์ฆ ๊ณต๊ฐ ์ค์ผ์ผ (ํด์๋ก ๊ฑฐ์น ํจํด)
[SerializeField] float speed = 0.5f; // ๋
ธ์ด์ฆ ์๊ฐ ์งํ ์๋
[Header("Gradient Colors")]
[SerializeField] Color colorA = new Color(0.05f, 0.10f, 0.30f, 1f); // ๋
ธ์ด์ฆ 0 ์ชฝ ์
[SerializeField] Color colorB = new Color(0.90f, 0.40f, 0.20f, 1f); // ๋
ธ์ด์ฆ 1 ์ชฝ ์
[Header("Editor Preview")]
[SerializeField] bool showInSceneEditor = true; // ์ฌ ๋ทฐ ๋ฏธ๋ฆฌ๋ณด๊ธฐ ํ์ฑ ์ฌ๋ถ
[SerializeField] float editorPreviewTime = 0f; // ์๋ํฐ ๋ชจ๋์์ ์ฌ์ฉํ ๊ฐ์ ์๊ฐ๊ฐ
// ----------------------------------------------------------------
// ๋ด๋ถ ๋ฐํ์ ์ํ
// ----------------------------------------------------------------
RenderTexture rt; // GPU์ ํ ๋น๋ ๊ฒฐ๊ณผ ํ
์ค์ฒ
MaterialPropertyBlock mpb; // ๋จธํฐ๋ฆฌ์ผ ์ธ์คํด์ค ์์ด ํ๋กํผํฐ๋ฅผ ๋ฎ์ด์ฐ๋ ๋ธ๋ก
int kernel = -1; // CSMain ์ปค๋ ์ธ๋ฑ์ค (-1 = ์์ง ํ์ ์ )
int prevW = -1; // ์ด์ ๋๋น โ ํด์๋ ๋ณ๊ฒฝ ๊ฐ์ง์ฉ
int prevH = -1; // ์ด์ ๋์ด โ ํด์๋ ๋ณ๊ฒฝ ๊ฐ์ง์ฉ
bool ready; // ๋ ๋๋ง ๊ฐ๋ฅ ์ํ ํ๋๊ทธ (์ด๊ธฐํ ์ฌ๋ถ)
// ----------------------------------------------------------------
// ์
ฐ์ด๋ ํ๋กํผํฐ ID ์บ์ฑ
// Shader.PropertyToID() ๋ ๋งค ํ๋ ์ ํธ์ถ ์ ๋น์ฉ์ด ์์ผ๋ฏ๋ก
// static readonly ๋ก ํ ๋ฒ๋ง ํด์ํํด ์ฌ์ฌ์ฉํฉ๋๋ค.
// ----------------------------------------------------------------
static readonly int ID_Result = Shader.PropertyToID("Result");
static readonly int ID_Width = Shader.PropertyToID("_Width");
static readonly int ID_Height = Shader.PropertyToID("_Height");
static readonly int ID_Time = Shader.PropertyToID("_TimeValue");
static readonly int ID_Scale = Shader.PropertyToID("_Scale");
static readonly int ID_Speed = Shader.PropertyToID("_Speed");
static readonly int ID_ColorA = Shader.PropertyToID("_ColorA");
static readonly int ID_ColorB = Shader.PropertyToID("_ColorB");
static readonly int ID_BaseMap = Shader.PropertyToID("_BaseMap"); // URP / HDRP
static readonly int ID_MainTex = Shader.PropertyToID("_MainTex"); // Built-in RP
// ์ปดํจํธ ์
ฐ์ด๋์ [numthreads(8, 8, 1)] ๊ณผ ๋ฐ๋์ ์ผ์นํด์ผ ํฉ๋๋ค.
// ์
ฐ์ด๋ numthreads ๋ฅผ ๋ฐ๊พธ๋ฉด ์ด ๊ฐ๋ ํจ๊ป ์์ ํ์ธ์.
const int THREAD_GROUP_SIZE = 8;
// ================================================================
// Unity ์๋ช
์ฃผ๊ธฐ
// ================================================================
void OnEnable() // ์ปดํฌ๋ํธ๊ฐ ํ์ฑํ๋ ๋ ํธ์ถ
{
// ํ์ฑํ ์ ์ด๊ธฐํ ํ ์ฆ์ ํ ๋ฒ ๋ ๋๋งํด ๋น ํ๋ฉด์ ๋ฐฉ์งํฉ๋๋ค.
EnsureInit(); // ์ด๊ธฐํ ํ์ธ
RenderNow(); // ์ฆ์ ๋ ๋๋งํด์ ๋น ํ๋ฉด ๋ฐฉ์ง
}
void OnDisable() // ์ปดํฌ๋ํธ๊ฐ ๋นํ์ฑํ๋ ๋ ํธ์ถ
{
// ๋นํ์ฑํ ์ ๋ ๋๋ฌ์์ ํ
์ค์ฒ ์ฐธ์กฐ๋ฅผ ๋จผ์ ๋์ ๋ค GPU ๋ฆฌ์์ค๋ฅผ ํด์ ํฉ๋๋ค.
// ์์๊ฐ ๋ฐ๋๋ฉด ๋ ๋๋ฌ๊ฐ ์ด๋ฏธ ํด์ ๋ ํ
์ค์ฒ๋ฅผ ์ ์ ์ฐธ์กฐํ๊ฒ ๋ฉ๋๋ค.
ClearPropertyBlockTexture(); // ํ๋กํผํฐ ๋ธ๋ก ํ
์ค์ณ ์ด๊ธฐํ
ReleaseAll(); // ๋ชจ๋ ๋ฆฌ์์ค ํด์
}
void OnDestroy()
{
// OnDisable ์ด ํญ์ ๋จผ์ ํธ์ถ๋์ง๋ง, ์๋ธํด๋์ฑ ๋ฑ ํ์ฅ์ ๊ณ ๋ คํด
// ๋ช
์์ ์ผ๋ก ํ ๋ฒ ๋ ์ ๋ฆฌํฉ๋๋ค. ReleaseAll ์ ์ค๋ณต ํธ์ถ์ ์์ ํฉ๋๋ค.
ReleaseAll();
}
void OnValidate() // ์ธ์คํํฐ ๊ฐ์ด ๋ณ๊ฒฝ๋ ๋ ํธ์ถ
{
// Range / Min ์ดํธ๋ฆฌ๋ทฐํธ๊ฐ ์ด๋ฏธ ํด๋จํ์ ๋ด๋นํ์ง๋ง,
// ์ฝ๋๋ก ์ง์ ๊ฐ์ ๋ฃ๋ ๊ฒฝ์ฐ๋ฅผ ๋๋นํ ๋ฐฉ์ด ์ฒ๋ฆฌ์
๋๋ค.
width = Mathf.Max(32, width); // ๋๋น ์ต์๊ฐ ์ค์
height = Mathf.Max(32, height); // ๋์ด ์ต์๊ฐ ์ค์
scale = Mathf.Max(0.01f, scale); // ์ค์ผ์ผ ์ต์๊ฐ ์ค์
// OnValidate ๋ ์๋ํฐ ์ง๋ ฌํ ์ฝ๋ฐฑ์ผ๋ก ํ์ด๋ฐ์ด ๋ถ์์ ํ ์ ์์ต๋๋ค.
// ์ปดํฌ๋ํธ๊ฐ ๋นํ์ฑ ์ํ๋ผ๋ฉด GPU ์์
์ ์๋ํ์ง ์์ต๋๋ค.
if (!isActiveAndEnabled) return; // ํ์ฑํ๋์ง ์์๋ค๋ฉด ์ข
๋ฃ
EnsureInit(); // ์ด๊ธฐํ ํ์ธ
RenderNow(); // ์ฆ์ ๋ ๋๋ง
}
void Update() // ๋งค ํ๋ ์ ํธ์ถ
{
if (!isActiveAndEnabled) return; // ํ์ฑํ๋์ง ์์๋ค๋ฉด ์ข
๋ฃ
if (!EnsureInit()) return; // ์ด๊ธฐํ ์คํจ ์ ์ข
๋ฃ
if (Application.isPlaying)
{
RenderNow(); // ํ๋ ์ด ๋ชจ๋ โ ๋งค ํ๋ ์ ๊ฐฑ์ (Time.time ๊ธฐ๋ฐ ์ ๋๋ฉ์ด์
)
return;
}
// ์๋ํฐ ๋ชจ๋ โ ์ฌ ๋ทฐ ๋ฏธ๋ฆฌ๋ณด๊ธฐ๊ฐ ์ผ์ง ๊ฒฝ์ฐ์๋ง ๋ ๋๋ง
if (showInSceneEditor) RenderNow();
}
// ================================================================
// ์ด๊ธฐํ
// ================================================================
// ์ปค๋ ํ์ โ RenderTexture ์์ฑ โ MPB ์ค๋น๋ฅผ ์์๋๋ก ์ํํฉ๋๋ค.
// ์ด๋ฏธ ์ค๋น๋ ์ํ๋ฉด ๋ณ๊ฒฝ๋ ๋ถ๋ถ๋ง ์ฌ์ฒ๋ฆฌํฉ๋๋ค.
// ๋ฐํ๊ฐ: ๋ ๋๋ง ๊ฐ๋ฅ ์ฌ๋ถ
bool EnsureInit()
{
if (compute == null || targetRenderer == null)
{
ready = false; // Compute Shader๋ ๋ ๋๋ฌ๊ฐ ์์ผ๋ฉด ์ค๋น ์๋ฃ ์๋
return false;
}
// ์ปค๋ ์ธ๋ฑ์ค๊ฐ ์์ง ์์ผ๋ฉด ํ์ํฉ๋๋ค.
if (kernel < 0)
{
if (!compute.HasKernel("CSMain"))
{
Debug.LogError("[ComputePreview] ์ปดํจํธ ์
ฐ์ด๋์ 'CSMain' ์ปค๋์ด ์์ต๋๋ค.", this);
ready = false; // ์ปค๋์ด ์์ผ๋ฉด ์ค๋น ์๋ฃ ์๋
return false;
}
kernel = compute.FindKernel("CSMain"); // ์ปค๋ ID ๊ฐ์ ธ์ค๊ธฐ
}
// ํด์๋๊ฐ ๋ฐ๋์๊ฑฐ๋ ํ
์ค์ฒ๊ฐ ์์ผ๋ฉด ์ฌ์์ฑํฉ๋๋ค.
if (rt == null || prevW != width || prevH != height)
CreateRT(); // ๋ ๋ ํ
์ค์ฒ ์์ฑ ๋๋ ๊ฐฑ์
if (mpb == null)
mpb = new MaterialPropertyBlock(); // ๋ ๋ ํ
์ค์ฒ ์์ฑ ๋๋ ๊ฐฑ์
// rt.IsCreated() ๋ก GPU ์์ ์ค์ ์์ฑ ์ฌ๋ถ๋ฅผ ๊ฒ์ฆํฉ๋๋ค.
// rt.Create() ๊ฐ ์คํจํด๋ rt != null ์ด๋ฏ๋ก ์ด ์ฒดํฌ๊ฐ ํ์ํฉ๋๋ค.
ready = rt != null && rt.IsCreated() && kernel >= 0;
return ready;
}
// ํ์ฌ ํด์๋ ์ค์ ์ผ๋ก RenderTexture ๋ฅผ ์๋ก ์์ฑํฉ๋๋ค.
// enableRandomWrite = true ๋ ์ปดํจํธ ์
ฐ์ด๋์ RWTexture2D ๋ฐ์ธ๋ฉ์ ํ์์
๋๋ค.
void CreateRT()
{
ReleaseRT(); // ๊ธฐ์กด ํ
์ค์ฒ๊ฐ ์์ผ๋ฉด ๋จผ์ ํด์
rt = new RenderTexture(width, height, 0, RenderTextureFormat.ARGB32); // ์๋ก์ด ๋ ๋ ํ
์ค์ฒ ์์ฑ
rt.enableRandomWrite = true; // ๋๋ค ์ฐ๊ธฐ ํ์ฑํ
rt.wrapMode = TextureWrapMode.Repeat; // ํ
์ค์ฒ ๋ฐ๋ณต ๋ชจ๋
rt.filterMode = FilterMode.Bilinear; // ํํฐ ๋ชจ๋ ์ค์
if (!rt.Create())
{
// GPU ํ
์ค์ฒ ์์ฑ ์คํจ โ ํด์๋๊ฐ ๋๋ฌด ํฌ๊ฑฐ๋ VRAM ๋ถ์กฑ์ผ ์ ์์ต๋๋ค.
Debug.LogError(
$"[ComputePreview] RenderTexture ์์ฑ ์คํจ ({width}x{height}). " +
"ํด์๋๋ฅผ ๋ฎ์ถ๊ฑฐ๋ GPU ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํ์ธํ์ธ์.", this);
DestroyImmediate(rt);
rt = null;
return;
}
prevW = width; // ์ด์ ๋๋น ์ ์ฅ
prevH = height; // ์ด์ ๋์ด ์ ์ฅ
}
// ================================================================
// ๋ ๋๋ง
// ================================================================
// ํ๋ ์ด ๋ชจ๋ โ Time.time (์ค์ ๊ฒฝ๊ณผ ์๊ฐ)
// ์๋ํฐ ๋ชจ๋ โ editorPreviewTime (์ธ์คํํฐ์์ ์๋ ์ค์ )
float GetTimeValue() // ํ์ฌ ์๊ฐ ๊ฐ ๊ฐ์ ธ์ค๊ธฐ
{
return Application.isPlaying ? Time.time : editorPreviewTime;
}
// ์ปดํจํธ ์
ฐ์ด๋์ ํ๋ผ๋ฏธํฐ๋ฅผ ์ ๋ฌํ๊ณ Dispatch ํ ๋ค,
// ๊ฒฐ๊ณผ ํ
์ค์ฒ๋ฅผ MPB ๋ฅผ ํตํด ๋ ๋๋ฌ์ ๋ฐ์ํฉ๋๋ค.
void RenderNow()
{
if (!ready || compute == null || rt == null || kernel < 0) return;
compute.SetTexture(kernel, ID_Result, rt);
compute.SetInt (ID_Width, width);
compute.SetInt (ID_Height, height);
compute.SetFloat (ID_Time, GetTimeValue());
compute.SetFloat (ID_Scale, scale);
compute.SetFloat (ID_Speed, speed);
compute.SetVector(ID_ColorA, colorA);
compute.SetVector(ID_ColorB, colorB);
// ์ค๋ ๋ ๊ทธ๋ฃน ์ = ํ
์ค์ฒ ํฌ๊ธฐ / numthreads ํฌ๊ธฐ (์ฌ๋ฆผ)
// ์: 512 / 8 = 64 ๊ทธ๋ฃน โ 64 * 8 = 512 ์ค๋ ๋๋ก ์ ์ฒด ํฝ์
์ ์ปค๋ฒ
int gx = Mathf.CeilToInt(width / (float)THREAD_GROUP_SIZE);
int gy = Mathf.CeilToInt(height / (float)THREAD_GROUP_SIZE);
compute.Dispatch(kernel, gx, gy, 1);
ApplyPropertyBlockTexture();
}
// ================================================================
// MaterialPropertyBlock ๊ด๋ฆฌ
// ================================================================
// ๋ ๋๋ฌ์ MPB ์ ์์ฑ๋ ํ
์ค์ฒ๋ฅผ ์ ์ฉํฉ๋๋ค.
// _BaseMap(URP/HDRP) ๊ณผ _MainTex(Built-in RP) ๋ฅผ ๋ชจ๋ ์ค์ ํด
// ๋ ๋ ํ์ดํ๋ผ์ธ์ ๊ด๊ณ์์ด ๋์ํ๋๋ก ํฉ๋๋ค.
void ApplyPropertyBlockTexture()
{
if (targetRenderer == null || rt == null) return;
if (mpb == null) mpb = new MaterialPropertyBlock();
targetRenderer.GetPropertyBlock(mpb); // ๊ธฐ์กด MPB ๊ฐ์ ์ ์งํ ์ฑ ๊ฐ์ ธ์ต๋๋ค.
mpb.SetTexture(ID_BaseMap, rt);
mpb.SetTexture(ID_MainTex, rt);
targetRenderer.SetPropertyBlock(mpb);
}
// ๋ ๋๋ฌ์์ ํ
์ค์ฒ ์ฐธ์กฐ๋ฅผ ์ ๊ฑฐํฉ๋๋ค.
// SetTexture(..., null) ์ Unity ๋ฒ์ ์ ๋ฐ๋ผ ๊ฒฝ๊ณ /์์ธ๊ฐ ๋ฐ์ํ ์ ์์ผ๋ฏ๋ก
// mpb.Clear() ๋ก ๋ธ๋ก ์ ์ฒด๋ฅผ ์ด๊ธฐํํ๋ ๋ฐฉ์์ ์ฌ์ฉํฉ๋๋ค.
void ClearPropertyBlockTexture()
{
if (targetRenderer == null) return;
if (mpb == null) mpb = new MaterialPropertyBlock();
mpb.Clear();
targetRenderer.SetPropertyBlock(mpb);
}
// ================================================================
// GPU ๋ฆฌ์์ค ํด์
// ================================================================
// [ExecuteAlways] ํ๊ฒฝ์์๋ Destroy() ๋์ DestroyImmediate() ๋ฅผ ์ฌ์ฉํด์ผ
// ์๋ํฐ ๋ชจ๋์์ ์ฆ์ ํด์ ๋ฉ๋๋ค. (Destroy ๋ ํ๋ ์ด ๋ชจ๋์์๋ง ๋์)
void ReleaseRT()
{
if (rt == null) return;
rt.Release(); // GPU ๋ฉ๋ชจ๋ฆฌ ๋ฐํ (ํ
์ค์ณ ํด์ )
DestroyImmediate(rt); // ๋ ๋ ํ
์ค์ณ ์ฆ์ ์ญ์
rt = null; // ์ฐธ์กฐ ์ด๊ธฐํ
}
// ๋ชจ๋ GPU ๋ฆฌ์์ค์ ๋ด๋ถ ์ํ๋ฅผ ์ด๊ธฐํํฉ๋๋ค.
// kernel ์ -1 ๋ก ๋ฆฌ์
ํด ๋ค์ EnsureInit() ํธ์ถ ์ ์ฌํ์ํ๋๋ก ํฉ๋๋ค.
void ReleaseAll()
{
ReleaseRT(); // ๋ ๋ ํ
์ค์ณ ํด์
kernel = -1; // ์ปค๋ ID ์ด๊ธฐํ
ready = false; // ์ค๋น ์๋ฃ ์ํ ์ด๊ธฐํ
}
}