using UnityEngine; public class GPUGraph : MonoBehaviour { [SerializeField] ComputeShader computeShader = default; [SerializeField] Material material = default; [SerializeField] Mesh mesh = default; const int maxResolution = 1000; [SerializeField, Range(10, maxResolution)] int resolution = 10; [SerializeField] FunctionLibrary.FunctionName function = default; public enum TransitionMode { Normal, Cycle, Random } [SerializeField] TransitionMode transitionMode = TransitionMode.Normal; [SerializeField, Min(0.0f)] float functionDuration = 1.0f; [SerializeField, Min(0.0f)] float transitionDuration = 1.0f; float duration = 0.0f; bool transitioning; FunctionLibrary.FunctionName transitionFunction; ComputeBuffer positionsBuffer; static readonly int positionsId = Shader.PropertyToID("_Positions"); static readonly int resolutionId = Shader.PropertyToID("_Resolution"); static readonly int stepId = Shader.PropertyToID("_Step"); static readonly int timeId = Shader.PropertyToID("_Time"); private void OnEnable() { positionsBuffer = new ComputeBuffer(maxResolution * maxResolution, 3 * 4); } private void OnDisable() { positionsBuffer.Release(); positionsBuffer = null; } private void Update() { duration += Time.deltaTime; if (transitioning) { if (duration >= transitionDuration) { duration -= transitionDuration; transitioning = false; } } else if (duration >= functionDuration) { duration -= functionDuration; transitioning = true; transitionFunction = function; PickNextFunction(); } UpdateFunctionOnGPU(); } private void PickNextFunction() { if (transitionMode == TransitionMode.Normal) return; function = transitionMode == TransitionMode.Cycle ? FunctionLibrary.GetNextFunctionName(function) : FunctionLibrary.GetRandomFunctionNameOtherThan(function); } private void UpdateFunctionOnGPU() { var step = 2f / resolution; computeShader.SetInt(resolutionId, resolution); computeShader.SetFloat(stepId, step); computeShader.SetFloat(timeId, Time.time); computeShader.SetBuffer(0, positionsId, positionsBuffer); var groups = Mathf.CeilToInt(resolution / 8f); computeShader.Dispatch(0, groups, groups, 1); material.SetBuffer(positionsId, positionsBuffer); material.SetFloat(stepId, step); var bounds = new Bounds(Vector3.zero, Vector3.one * (2f + 2f / resolution)); Graphics.DrawMeshInstancedProcedural(mesh, 0, material, bounds, resolution * resolution); } }