관리 메뉴

caLAB

[Compute Shader 01] 컴퓨터 쉐이더의 기본 본문

Unity/유니티 Shader

[Compute Shader 01] 컴퓨터 쉐이더의 기본

도이(doi) 2021. 7. 29. 17:20
728x90

예전부터 관심을 가지고 있던 compute shader에 대해서 공부를 시작하려고 합니다. 

udemy에서 강좌를 결제해서 들으며 공부 과정을 정리하고자 합니다. 

compute shader를 공부하게 된 계기는 vfx graph를 사용하다보니 연산처리 과정을 compute shader에서 해서 가져오는 경우도 있고 이래저래 멋있는 기술은 항상 많은 공부를 요하기 때문에 공부를 시작하게 되었습니다.

compute shader의 기본적인 사용 방법에 대해서는 원래 알고 있었지만 이를 한 번 더 복기하고자 합니다.

 

우선, compute shader는 윈도우에서만 돌아간다고 생각을 하는데요. 

DirectX 11 스타일 HLSL 언어로 작성되어 있습니다. c언어와 유사한 점이 많습니다.

 

오늘 공부해볼 것은 구역에 따른 material pixel의 값을 조절하는 것입니다.

우선, compute shader를 작성하기 위해서는 두 개의 스크립트가 필요합니다.

   1. 일반 유니티 스크립트 (실행 스크립트)

   2. compute shader 스크립트 (연산 스크립트) 
* compute shader 생성 방법 : 우클릭 > Create > Shader > Compute Shader

커널, 스레드, 스레드 그룹 개념

dispatch와 numthread의 관계

dispatch는 compute shader 계산으로 numthread에서 3차원으로 구성한 그룹을 실행한다.

numthread는 작업 그룹 크기를 지정한다. 

 

compute shader에서 호출의 총량은 thread group의 수에 thread group의 크기를 곱한 것이다.

 

일반 스크립트 

using UnityEngine;
using System.Collections;

public class Challenge1 : MonoBehaviour
{
    public ComputeShader shader; //compute shader 가져오기 
    public int texResolution = 1024;

    Renderer rend;
    RenderTexture outputTexture;

    int kernelHandle; 

    void Start()
    {
        outputTexture = new RenderTexture(texResolution, texResolution, 0);
        outputTexture.enableRandomWrite = true;
        outputTexture.Create();

        rend = GetComponent<Renderer>();
        rend.enabled = true;

        InitShader();
    }

    private void InitShader()
    {
        //kernel 가져오기
        kernelHandle = shader.FindKernel("Square");

        int halfRes = texResolution >> 1; // texResolution / 2
        int quarterRes = texResolution >> 2; // texResolution / 4

        Vector4 rect = new Vector4( quarterRes, quarterRes, halfRes, halfRes );

        shader.SetVector( "rect", rect );
        //kernelhandle에 있는 result의 값을 outputTexture에 저장.
        shader.SetTexture(kernelHandle, "Result", outputTexture);
        //material에 outputTexture적용. 
        rend.material.SetTexture("_MainTex", outputTexture);
        //compute shader 실행
        DispatchShader(texResolution / 8, texResolution / 8);
    }

    //x, y는 thread group의 크기. 
    //resolution / thread를 하면 thread group의 크기를 구할 수 있다.
    private void DispatchShader(int x, int y)
    {
        shader.Dispatch(kernelHandle, x, y, 1);
    }
}

compute shader 스크립트 

//커널 이름
#pragma kernel Square 
//스크립트에서 값 설정할 변수 선언 
RWTexture2D<float4> Result; //최종 결과
float4 rect; //크기

//사각형 내부 값 판별 공식
float inSquare( float2 pt, float4 rect ){
    float horz = step( rect.x, pt.x ) - step( rect.x + rect.z, pt.x );
    float vert = step( rect.y, pt.y ) - step( rect.y + rect.w, pt.y );
    return horz * vert;
}

//적용 
[numthreads(8,8,1)]
void Square (uint3 id : SV_DispatchThreadID)
{
    float res = inSquare( (float2)id.xy, rect );

    Result[id.xy] = float4(0.0, 0.0, res, 1.0);
}

 

 

비트 연산자 개념

비트를 우측의 숫자만큼 이동시킴. 2배수 씩 차이남. 

 

유니티에서 사용되는 수학 함수 

 Function 설명 
 abs( x )  절대값 x를 반환합니다
 acos ( x )  아크코사인 값으로 x가 [-1 ~ 1]일때. [0 ~ p​] 를 반환합니다. 

 all ( x )  x의 모든 구성요소가 0이 아닐때 true를 반환하고 그 외의 값일때는 false를 반환합니다.
 any ( x )  x의 구성요소가 0이 아닐때 true를 반환하고 그 외의 값일때는 false를 반환합니다

 asine ( x )  아크사인 값으로 x가 [-1 ~ 1] 일떄, [p/2 ~ p/2] 를 반환합니다
 atan ( x )  아크탄젠트 값으로 x값(-∞ < x < )에 따라 [p/2 ~ p/2] 에 무한히 가까운 값을 반환합니다 
 atan2 ( x )  아크탄젠트 값으로 atan과 같지만 밑변분의 높이값으로 계산하면 반환
 ceil ( x )   x 이상인 값중에 가장 작은 정수값을 반환
 clamp (x , a, b)  x가 a보다 낮으면 a반환, x가 b보다 크면 b반환, 그 사이값이면 x를 반환
 cos ( x )  코사인 x값을 반환
 cosh ( x )  하이퍼볼릭코사인(쌍곡선) x의 값을 반환
 cross ( a, b )  a 벡터와 b 벡터의 외적을 반환
 degrees ( x )  라디안을 도로 변환
 determinant ( m )  행렬m의 행렬식(?)
 dot ( a, b )  벡터 a와 벡터 b의 내적을 반환
 exp ( x )  e의 x승 을 반환
 exp2 ( x )  2의 x승 을 반환 
 floor ( x )  x 보다 크지 않은 정수중 가장 큰 정수를 반환 (반 내림)
 fmod ( x, y )  x 를 y 로 나누었을 때 나머지를 반환
 frac ( x )  
 frexp ( x, out exp )  
 isfinite ( x )  x가 무한대수가 아니면 true를 반환 
 isinf ( x )  x가 무한대수면 true를 반환 
 isnan ( x )  x가 숫자가 아니면 true를 반환
 ldexp ( x, n )  x * 2의 n승 을 반환 
 lerp ( a, b, f ) ​벡터a 와 벡터b 의 선형보간으로 f가 0~1사이의 값을 넣어 a와 b의 비율에 맞는 벡터값 반환
 lit ( NdotL . NdotH , m)  
 log ( x )  자연로그 x의 값을 반환 (x는 0보다 커야함)
 log2 ( x )  밑이 2인 로그 x의 값을 반환 (x는 0보다 커야함)
 log10 ( x )  밑이 10인 로그 x의 값을 반환 (x는 0보다 커야함) 
 max ( a, b )  a와 b의 값중에 큰 값을 반환 
 min ( a, b )  a와 b의 값중에 작은 값을 반환 
 modf ( x , out ip )  x를 정수와 소수로 나눠주는 함수로 정수는 ip에 저장, 소수부분을 반환
 mul ( M, N )  햏렬 M과 행렬 N을 곱한값을 행렬로 반환 
 mul ( v , M )  벡터v와 행렬M을 곱한값을  행렬로 반환
 mul ( M , v)  행렬M과 벡터v를 곱한값을 벡터로 반환 
 noise ( x )   
 pow ( x, y )  x의 y승을 반환 
 radians ( x )  x도를 라디안으로 변환하여 반환
 round ( x )  x와 가장 가까운 정수값을 반환 (반내림 혹은 반올림) 
 rsqrt ( x )  루트x 를 반환한다. (x는 0보다 커야한다)
 saturate ( x )  clamp (x , 0.0f, 1.0f)를 반환한다
 sign ( x )  x가 양수면 1, x가 음수면 -1, 0이면 0을 반환
 sin ( x )  사인 x값을 반환 
 sincos( x, out s, out c )  s에는 사인x값, c에는 코사인x값이 들어간다. sin(x), cos(x)를 각각 계산하는것보다 효율적이다
 sinh ( x )  하이퍼볼릭 사인 x의 값을 반환 
 smoothstep ( min, max, x )  min과 max값을 보간해주며 x의 값이 0.0f에서 1.0f의 값을 가지며 x가 1.0f에 가까울 수록 적은 보간이 된다
 step ( a, x )  x 가 a보다 작으면 0을 반환, x가 a보다 크거나 같으면 1을 반환 
 sqrt ( x )  x의 제곱근을 반환 (x는 0보다 커야 한다)
 tan ( x )  탄젠트x를 반환 
 tanh ( x )  하이퍼볼릭 탄젠트 x를 반환 
 transpose ( m )  행렬M의 전치행렬M을 반환
[출처] Unity3d Shader - 7. Surface Shader 수학함수|작성자 토이박스

 

[응용]

update문에서 compute shader를 실행하여 큐브의 위치에 따라서 색상이 변하게 만든다. 

728x90
반응형
Comments