본문 바로가기
유니티/Shader Study

유니티에서 HLSL으로 Voronoi custom 을 만들어 유용하게 쓰는 방법

by witn331ss 2024. 1. 21.

최근 프로젝트를 진행하면서 물결을 만들 필요성이 생겼다.

블렌더 셰이더 내에서 보로노이를 자유롭게 조절할 수 있는 것이 생각나서 (아니면 less than)으로 사용하고 싶은 부분만 빼는 방식으로 문제해결을 하려고 했었다.

 

 

하지만 인생사 그렇게 간단히 끝날리가 없다.

정확히는 랜덤연산이 필요하고 조금 더 샤프하게 표현될 모델이 필요했다.

근데 여기서 샤프하게 표현하려고 내가 가진 지식들을 총 동원해도

 

이렇게 나오는 것 아닌가.. (이건 내가 잘 몰라서 그런 것도 있을 것이다)

그래서 이건 커스텀된 모델을 찾아서 적용하는게 맞다고 판단했다.

 

 

일단 보로노이가 어떤 방식으로 작동하는지 알아야했다.

 

 

일단 지금 유니티에서 제공하는 보로노이에 무슨 문제가 있는 것인지 살펴보자

 

 

각 영역에 대한 점과 임의의 값을 임의의 RGB색상으로 내보낼 수 있지만

이 영역을 분리하는 가장자리에 대한 정보를 출력하지 않게 되어있다.

 

그라데이션을 찾는 DDXY노드를 사용할 순 있지만

 

너비를 구할 수가 없다 너비를!! 난 두껍게도 만들고 싶다!!

 

즉, 이건 직접 연산을 해줘야 하는 수고로움이 필연적으로 생긴다.

 

inline float2 randomVector (float2 UV, float offset)
{
    float2x2 m = float2x2(15.27, 47.63, 99.41, 89.98);
    UV = frac(sin(mul(UV, m)) * 46839.32);
    return float2(sin(UV.y*+offset)*0.5+0.5, cos(UV.x*offset)*0.5+0.5);
}

void CustomVoronoi_float(float2 UV, float AngleOffset, float CellDensity, out float DistFromCenter, out float DistFromEdge)
{
    int2 cell = floor(UV * CellDensity);
    float2 posInCell = frac(UV * CellDensity);

    DistFromCenter = 8.0f;
    float2 closestOffset;

    for(int y = -1; y <= 1; ++y)
    {
        for(int x = -1; x <= 1; ++x)
        {
            int2 cellToCheck = int2(x, y);
            float2 cellOffset = float2(cellToCheck) - posInCell + randomVector(cell + cellToCheck, AngleOffset);

            float distToPoint = dot(cellOffset, cellOffset);

            if(distToPoint < DistFromCenter)
            {
                DistFromCenter = distToPoint;
                closestOffset = cellOffset;
            }
        }
    }

    DistFromEdge = 8.0f;

    for(int y = -1; y <= 1; ++y)
    {
        for(int x = -1; x <= 1; ++x)
        {
            int2 cellToCheck = int2(x, y);
            float2 cellOffset = float2(cellToCheck) - posInCell + randomVector(cell + cellToCheck, AngleOffset);

            float distToEdge = dot(0.5f * (closestOffset + cellOffset), normalize(cellOffset - closestOffset));

            DistFromEdge = min(DistFromEdge, distToEdge);
        }
    }
}

 

 

 

이걸 적용하면 우리가 이전에 볼 수 있던 보로노이 패턴이 생겼다!

 

이렇게 이용해먹으면 되니 잘 활용하길 바란다.