티스토리 뷰

Unity/Shader Graph

Voronoi

연홍 2021. 1. 15. 13:23
728x90

입력UV를 기반으로 Voronoi 또는 Worley 노이즈를 생성합니다. 보로노이 노이즈는 픽셀과 점격자 사이의 거리를 계산하여 생성합니다. Angle Offset에 의해 제어되는 의사랜덤값으로 점을 조절함으로써 셀 클러스터를 생성 할 수 있습니다. 이러한 셀의 크기와 결과 노이즈는 Cell Density에 의해 제어됩니다 . output셀에는 raw셀 데이터가 포함됩니다.

일반적으로 가장 가까운 지점까지의 거리를 F1 Voronoi. 두번째로 가까운 지점까지의 거리를 출력하는 것을 F2 Voronoi, 세번째로 가장 가까운 지점은 F3으로 표현합니다.

 

Shadergraph에는 F1 Voronoi (일반 유클리드 거리를 사용하여 가장 가까운 지점까지의 거리)를 출력 하는 내장 Voronoi 노드를 사용합니다.

inline float2 unity_voronoi_noise_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 Unity_Voronoi_float(float2 UV, float AngleOffset, float CellDensity, out float Out, out float Cells)
{
    float2 g = floor(UV * CellDensity);
    float2 f = frac(UV * CellDensity);
    float t = 8.0;
    float3 res = float3(8.0, 0.0, 0.0);

    for(int y=-1; y<=1; y++)
    {
        for(int x=-1; x<=1; x++)
        {
            float2 lattice = float2(x,y);
            float2 offset = unity_voronoi_noise_randomVector(lattice + g, AngleOffset);
            float d = distance(lattice + offset, f);
            if(d < res.x)
            {
                res = float3(d, offset.x, offset.y);
                Out = res.x;
                Cells = res.y;
            }
        }
    }
}

이 셰이더가 plane 또는 quad에 적용된다고 가정하면 UV는 평면을 따라 0~1값을 갖습니다. 여기에 CellDensity값을 곱한 다음 floor를 취하여 UV를 따라 정수 좌표를 구하여 g라는 변수에 포함된 셀 그리드를 생성합니다 . 또한 g와 유사하지만 floor 대신 frac함수를 사용 하는 변수 f를 얻습니다 . 

이후에 x 및 y 축 모두에 대해 -1 과 1 사이의 루프를 사용하여 인접셀을 반복합니다. 여기서 셀의 위치는 lattice+g로 지정합니다 . unity_voronoi_noise_randomVector 함수는 AngleOffset 변수와 셀 위치를 함께 사용하여 임의의 방향을 가리키는 float2 오프셋 벡터를 생성합니다.

랜덤 벡터 오프셋 과 함께 추가된 격자값 (셀 오프셋)은 이제 해당 셀 내부의 임의지점의 로컬 위치를 얻습니다. 이를 셀 내부 픽셀의 로컬위치인 f 와 비교하여 이들 사이의 거리를 얻을 수 있습니다. 그런 다음 res.x에 저장하여 더 작은지 확인하고 루프에서 가장 작은 거리를 찾기 위해 교체합니다.

Voronoi Edges

F1출력은 얼음, 망치 담금질한 금속과 같은 일부 재질에 유용할 수 있으며, 보로노이노이즈가 생성하는 거친 모양이나 edge를 사용하는것이 유용합니다. (예. 갈라진 땅 텍스처)

그러나 이것은 Voronoi 노드를 사용하여 수행 할 수 없습니다.이 작업을 수행하려면 Custom Function 노드를 사용하여 자체 Voronoi 함수를 작성해야 합니다.

보로노이의 edge를 얻는 가장 쉬운 방법은 F2보로노이를 얻고 여기에서 F1보로노이 를 빼는것입니다. 이 방법은 그다지 정확하지 않으며 일부 cell에서는 조금 이상하게 보일 수 있지만 더 빠릅니다. 더 정확한 방법은 두 개의 루프를 사용하는 것입니다. 하나는 가장 가까운 셀을 계산하는 것이고, 두 번째는 가장 가까운 셀과 인접한 셀 사이의 가장 가까운 edge를 계산하는 것입니다.

Voronoi Edges (F2-F1)

F2 Voronoi를 얻기 위해 Voronoi 노드를 약간 변경하면됩니다. 원래 코드에서는 "float3 res"값 (결과의 짧은거리 라고 가정)이 있는데, 여기서 res.x는 루프에서 현재 가장 가까운 지점을 추적합니다. res.y 및 res.z를 사용하여 셀 내부의 점을 오프셋하는 데 사용되는 임의의 벡터를 추적합니다. 하지만 res.z는 실제로 출력으로 사용되지 않으므로 대신 res.y에서 두 번째로 가까운 지점을 추적하고 res.z를 해당 임의 벡터의 첫 번째 구성 요소로 설정했습니다.

또한 거리 함수를 내적 대신에 교체했습니다. 즉, 더 나은 성능을 위해 루프 내부에서 sqrt 부분을 수행하지 않고 거리 제곱을 얻습니다.

함수에서 Out 매개 변수는 X/R 컴포넌트의 F1 Voronoi와 float2 / Vector2의 Y/G 컴포넌트에 F2 Voronoi를 포함합니다. Custom Function 노드에서 Split을 사용하고 실제 Voronoi Edge를 얻기 위해 R 구성 요소에서 G를 빼야합니다.

inline float2 voronoi_noise_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 Voronoi_float(float2 UV, float AngleOffset, float CellDensity, out float2 Out, out float Cells) {
    float2 g = floor(UV * CellDensity);
    float2 f = frac(UV * CellDensity);
    float3 res = float3(8.0, 8.0, 8.0);
 
    for(int y=-1; y<=1; y++){
        for(int x=-1; x<=1; x++){
            float2 lattice = float2(x, y);
            float2 offset = voronoi_noise_randomVector(g + lattice, AngleOffset);
            float2 v = lattice + offset - f;
            float d = dot(v, v);
             
            if(d < res.x){
                res.y = res.x;
                res.x = d;
                res.z = offset.x;
            }else if (d < res.y){
                res.y = d;
            }
        }
    }
 
    Out = float2(sqrt(res.x), sqrt(res.y));
    Cells = res.z;
}

Voronoi Edges (2 Loops)

더 정확한 방법은 루프 두번돌아서 edge까지의 가장 짧은거리를 얻습니다.

inline float2 voronoi_noise_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 Voronoi_float(float2 UV, float AngleOffset, float CellDensity, out float Out, out float Cells) {
    float2 g = floor(UV * CellDensity);
    float2 f = frac(UV * CellDensity);
    float2 res = float2(8.0, 8.0);
    float2 ml = float2(0,0);
    float2 mv = float2(0,0);
 
    for(int y=-1; y<=1; y++){
        for(int x=-1; x<=1; x++){
            float2 lattice = float2(x, y);
            float2 offset = voronoi_noise_randomVector(g + lattice, AngleOffset);
            float2 v = lattice + offset - f;
            float d = dot(v, v);
 
            if(d < res.x){
                res.x = d;
                res.y = offset.x;
                mv = v;
                ml = lattice;
            }
        }
    }
 
    Cells = res.y;
 
    res = float2(8.0, 8.0);
    for(int y=-2; y<=2; y++){
        for(int x=-2; x<=2; x++){
            float2 lattice = ml + float2(x, y);
            float2 offset = voronoi_noise_randomVector(g + lattice, AngleOffset);
            float2 v = lattice + offset - f;
 
            float2 cellDifference = abs(ml - lattice);
            if (cellDifference.x + cellDifference.y > 0.1){
                float d = dot(0.5*(mv+v), normalize(v-mv));
                res.x = min(res.x, d);
            }
        }
    }
 
    Out = res.x;
}

이 기능의 대부분은 이 게시물 을기반으로합니다. 그러나 여기에서 예제를 기반으로 cellDifference 부분도 추가했습니다. (기술적으로 우리가 가장 가까운 셀에 있다면 v-mv는 0과 같아야하며, 이는 normalize (0)를 유발합니다. 나는 이것이 무한대를 반환한다고 믿기 때문에 최소 검사로 인해 무시되어야하지만 이런 종류의 동작은 이것은 잠재적으로 다른 플랫폼에서 예상치 못한 결과를 초래할 수 있으므로 추가 된 if 문은 이를 방지하기위한 것입니다). 이 작동 방식에 대한 자세한 내용은 두 기사를 모두 확인하십시오. 약간 다른 코드를 제공하지만 일반적인 아이디어는 동일합니다. 가장 큰 차이점은 루프에서 가장 가까운 점과 -2 및 2의 값을 포함하는 셀의 중앙에 두 번째 루프가있는 첫 번째 기사이며, 다른 기사에는 첫 번째 기사와 동일한 두 번째 루프가 있으며 값은 -1이고 1. 이것은 정확도 대 성능 문제 일 가능성이 높습니다.

 

 

'Unity > Shader Graph' 카테고리의 다른 글

World space UVs & Triplanar Mapping  (0) 2021.01.18
Screen Position  (0) 2021.01.15
Render Texture  (0) 2021.01.14
Vertex Displacement  (0) 2021.01.14
Fresnel Effect  (0) 2021.01.13
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/08   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31