computer shader particle

computer shader로 파티클 그릴때, Graphics.DrawProcedural를 사용하고 있는데 대략 뭔지 알아 보겠습니다.

Graphics.DrawProcedural는 Unity에서 CPU가 아닌 GPU에서 직접 버텍스를 생성해서 그리는 방식으로, 주로 커스텀 메쉬, 셰이더 기반 파티클, GPU 인스턴싱 등에 사용됩니다. 이 명령은 모바일에서 사용 가능하지만 몇 가지 제한 사항이 있습니다.

Graphics.DrawProcedural 자체는 **모바일(iOS, Android)**에서도 호출이 가능합니다.
단, GPU가 지원하는 기능과 그래픽 API에 의존합니다.
  • OpenGL ES 3.0 이상
  • Vulkan (Android)
  • Metal (iOS)

제한 사항

1. 셰이더 지원
  • 반드시 Compute Shader 또는 Vertex/Fragment Shader와 연동해서 사용해야 합니다.
  • OpenGL ES 3.1 이상이면 Compute Shader 지원이 가능하지만, OpenGL ES 3.0에서는 제한적입니다.
2. Instancing
  1. GPU Instancing을 같이 사용하면 성능이 좋아집니다.
  2. 모바일에서는 Instancing 지원이 GPU 성능과 드라이버에 따라 달라질 수 있습니다.

3. DrawProcedural 타입
  • MeshTopology.Triangles 또는 MeshTopology.Points 등 GPU가 이해할 수 있는 topology여야 합니다.
  • Graphics.DrawProceduralNow를 사용하면 즉시 렌더링, Graphics.DrawProcedural은 커맨드 버퍼에서 렌더링을 예약합니다.

4. 성능 고려
  • 고해상도 모바일 기기에서는 성능이 괜찮지만, 저사양 기기에서는 과도한 버텍스 처리로 프레임 드랍 가능.
  • 배치 수와 버텍스 수를 적절히 조절해야 합니다.

5. WebGL은 지원되지 않습니다.


언제 Graphics.DrawProcedural을 쓰나?
  • 파티클 시스템 직접 구현
  • GPU 기반 시뮬레이션
  • 메쉬 생성 비용 없이 대량 렌더링
  • Compute Shader + 렌더링 연계


화면 중앙에 빨간 화면을 그려 보겠습니다.




DrawProceduralExample.cs 파일
using UnityEngine;

public class DrawProceduralExample : MonoBehaviour
{
    public Material material;

    void OnRenderObject()
    {
        if (material == null)
            return;

        material.SetPass(0);

        // 삼각형 1개 → vertex 3개
        Graphics.DrawProceduralNow( MeshTopology.Triangles, 3);
    }
}

핵심
  • Mesh를 전혀 사용하지 않음
  • vertexID를 이용해 셰이더에서 정점을 계산 (SV_VertexID)
  • OnRenderObject()는 가장 간단하게 테스트하기 좋음
여기서, vertexID는 Graphics.DrawProcedural 호출 시 GPU가 자동으로 생성해서 vertex shader에 넘겨주는 정점 인덱스입니다.
OnRenderObject는 카메라가 씬의 모든 일반적인 오브젝트 렌더링을 끝낸 직후에 호출됩니다.

셰이더 파일은 unlit으로 생성 합니다.

DrawProcedural.shader 파일
Shader "Unlit/DrawProceduralExample"
{
    SubShader
    {
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            struct v2f
            {
                float4 pos : SV_POSITION;
            };

            v2f vert(uint vertexID : SV_VertexID)
            {
                v2f o;

                float2 positions[3];
                positions[0] = float2(0.0, 0.5);
                positions[1] = float2(-0.5, -0.5);
                positions[2] = float2(0.5, -0.5);

                o.pos = float4(positions[vertexID], 0, 1);
                return o;
            }

            fixed4 frag(v2f i) : SV_Target
            {
                return fixed4(1, 0, 0, 1); // 빨간색
            }
            ENDCG
        }
    }
}

사용 방법
  1. 빈 GameObject 생성
  2. DrawProceduralExample 스크립트 추가
  3. 새 Material 생성
  4. Shader → Unlit/DrawProceduralExample
  5. Material을 스크립트에 할당
  6. 실행 ▶️

왜 Mesh 없이도 정점이 생기나?

DrawProcedural은 이렇게 동작합니다:

  1. CPU가 말함
    👉 “정점 3개 그려라”

  2. GPU가 자동으로
    👉 vertexID = 0,1,2 생성

  3. Vertex Shader에서
    👉 vertexID로 위치 계산