본문 바로가기
Shader CG

1.5 도형 - Draw Circle 심화

by SimonLee 2023. 7. 18.

04 챕터 Draw Circle을 구현해봤습니다.

- https://graphicsimon.tistory.com/11?category=1119246 

 

조금더 응용버전으로 작성해 보겠습니다.

 

먼저 frag 함수에서 position * 2를 해서 -1 ~ 1 좌표계 범위로 만들어 보겠습니다.

다시 말씀드리면 -0.5 ~ 0.5 좌표계에서 2를 곱한 것 입니다.

 

radius는 0.5로 주어졌다고 가정합니다.

 

1) 기본 원 렌더링

lenght 함수는 벡터의 크기(길이)를 구합니다.

pt - center를 해서 벡터를 구한 뒤, 길이를 구하면

l각 픽셀과 center과의 거리 (len)가 나옵니다. 

len 값과 주어진 raidus과 비교하여, len이 거리가 작으면 0을 리턴하게 됩니다.

1을 빼주게 되니, 원 내부픽셀들은 전부 1의 값을 가지게 됩니다. 

float circle(float2 pt, float2 center, float radius) 
{
    float len = length(pt - center);
    return 1.0 - step(radius, len);
}

2) 경계가 스무스한 원 렌더링

smoothstep(a, b, x) 리턴 값은 다음과 같습니다.

a < x 경우 return 0

x > b 경우 return 1

a < x < b 경우 return 0 ~ 1

smoothstep 결과 값은

radius - edge의 distance보다 작은 픽셀의 거리의 경우 0 (초록색)

radius + edge의 distance보다 큰 픽셀의 거리의 경우 1 (원 밖 흰색)

radius - edge < len < radius + edge 경우는 0 ~ 1 리턴하게 됩니다.

 

그래서 1을 빼게 되면 원의 내부는 1이 되고,

edge * 2 영역 만큼은 보간이 되어 흐려지게 보이게 됩니다.

float circle(float2 pt, float2 center, float radius, bool soften)
{
    float len = length(pt - center);
    float edge = (soften) ? radius * 0.05 : 0.0;
    return 1.0 - smoothstep(radius - edge, radius + edge, len);
}

 

3) 겹선형 원 렌더링

이번에는 아래 그림처럼 겹선형 원을 렌더링 해봅시다.

생각을 해보면 큰 원에서 작은 원을 빼면 될 것 같습니다.

2번에서 smoothstep 적용한 비슷한 원리 입니다.

 

안쪽 파랑색 원 밖의 부분은 전부 1, 내부는 1

연한색 파랑색 원 밖의 부분은 전부 1, 내부는 1

 

안쪽 파랑색 영역 - 연한색 파랑색 영역을 하게되면, 

- 배경 흰색 부분은 둘다 1이기 때문에 0 됩니다.

- 연한색 부분만 1 - 0 = 1로 1이 됩니다.

float circle(float2 pt, float2 center, float radius, float line_width) 
{
    float len = length(pt - center);                               
    return step(radius - line_width / 2, len) - step(radius + line_width / 2, len);
}

 

Shader "SimonLee/Shader14Unlit"
{
    Properties
    {
        _Color("Color", Color) = (1.0,1.0,0,1.0)
        _Radius("Radius", Float) = 0.3
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float4 position : TEXCOORD1;
                float2 uv: TEXCOORD0;
            };
            
            v2f vert (appdata_base v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.position = v.vertex;
                o.uv = v.texcoord;
                return o;
            }
           
            fixed4 _Color;
            float _Radius;

            float circle(float2 pt, float2 center, float radius) 
            {
                float len = length(pt - center);
                return 1.0 - step(radius, len);
            }

            float circle(float2 pt, float2 center, float radius, bool soften)
            {
                float len = length(pt - center);
                float edge = (soften) ? radius * 0.05 : 0.0;
                return 1.0 - smoothstep(radius - edge, radius + edge, len);
            }

            float circle(float2 pt, float2 center, float radius, float line_width) 
            {
                float len = length(pt - center);                               
                return step(radius - line_width / 2, len) - step(radius + line_width / 2, len);
            }

            fixed4 frag (v2f i) : SV_Target
            {
                float2 pos = i.position * 2;
                float2 center = (0, 0);
                //fixed3 color = _Color * circle(pos, center, _Radius);
                //fixed3 color = _Color * circle(pos, center, _Radius, true);
                fixed3 color = _Color * circle(pos, center, _Radius, 0.05);
                return fixed4(color, 1.0);
            }
            ENDCG
        }
    }
}

'Shader CG' 카테고리의 다른 글

2.1 Noise TV 화면 만들어보기  (0) 2023.08.06
1.6 도형 - 라인 그려보기  (0) 2023.07.20
1.4 도형 - 타일링  (0) 2023.07.13
1.3 도형 - Rotation & Scailing Rect  (0) 2023.07.11
1.2 도형 - Draw Rectangle - 2  (0) 2023.07.09