이번에 Random 함수를 사용해서 아래 모양을 만들어 봅시다.
위 그림을 처음 보면 복잡해 보여서 미로를 구성하는 벽이 굉장히 다양하게 있을것 같습니다.
선의 방향이 달라지는 부분을 기준으로 칸을 나누어 보면
한칸에 해당하는 선은 y=x 방향 y=-x+1 두개의 직선만 존재하는 것을 알수 있습니다.
음 2개 제외하고 다른 직선은 없습니다.
먼저 라인을 그려보는 것을 복습해 봅시다.
모르시는 분은 아래 링크 클릭!
https://graphicsimon.tistory.com/18
10. Draw Lines
라인도 대각선 방향으로된 사각형의 영역이라고 생각하시면 됩니다. 사각형의 경우 렌더링 방법은 좌측하단 꼭지점과 우측 상단 꼭지점을 기준으로 영역을 지정하고, 좌측하단 꼭지점 영역 -
graphicsimon.tistory.com
아래 코드는 라인을 그리는 함수 인데, reverse라는 파라메터가 있습니다.
위 파라메터가 false 이면, y = x 그래프 모양의 라인을 그립니다.
위 파라메터가 true 이면, y = -x + 1 그래프 모양의 라인을 그립니다.
당연하게 y = -x + 1 그래프는 아래 모양이겠지요 ? ^^
float Line(float2 st, float thick, float blur, bool reverse)
{
if (reverse)
{
st.x = -st.x + 1;
}
return smoothstep(st.x - thick - blur, st.x - thick + blur, st.y) -
smoothstep(st.x + thick - blur, st.x + thick + blur, st.y);
}
이제 저 선을 반복해서 그려야 하는데,
반복되는 구간이 가로 10칸, 세로 10칸 입니다.
좌표를 확장하는 방법은 어떻게 하지요 ? 좌표에 몇배 확장 할 것인지 곱해주면 됩니다.
i.uv *= 10;
그리고 나서 frac함수의 리턴 값인 소수값을 좌표로 사용하면, 10개의 구간이 나뉘어 지는 것을
저번 챕터에서 했습니다.
i.uv *= 10;
float2 fpos = frac(i.uv);
float3 color = float3(1, 0, 0);
color *= Line(fpos, 0.1, 0.05, false);
return float4(color, 1.0);
다음 처럼 선이 렌더링 됩니다.
랜덤함수를 적용해 봅시다.
랜덤 함수는 저번에 사용한 것과 동일한 것을 사용합니다.
랜덤 값의 리턴값은 float 이며, 이 값의 범위는 0 ~ 1 사이 입니다.
이 랜덤함수의 리턴 값은 확률이라고도 볼수가 있습니다.
float random(float2 pt) {
const float a = 12.9898;
const float b = 78.233;
const float c = 43758.543123;
return frac(sin(dot(pt, float2(a, b))) * c);
}
이 확률 값으로 비교하여
50%는 y = x 모양의 라인을 그리고, 50% 이하는 y = x - 1 모양의 라인을 그리면 될 것 같습니다.
그런데 저 10개로 나뉘어진 한칸의 영역을 어떻게 구분할수 있을까요 ?
쉐이더 개념에서 다시 말해보면,
가장 좌측 하단 선분이 있는 칸을 (0,0) 칸이라고 가정합시다.
저 한칸의 영역에 해당하는 수백개의 픽셀들이 동일하게 (0, 0) 칸에 포함 되는 것을 알 수 있어야 합니다.
그래야 (0, 0) 칸 에 해당하는 픽셀들에 대해 y = x 라인을 그려! 라고 할수 있는 것이지요
floor 함수를 사용하면 정수부분을 가져옵니다.
위에서 좌표를 10배로 확장시켰으니, 각 영역마다 0~9의 정수를 가져오겠네요.
float2 pos = floor (i.uv) 식을 적용하게 되면,
(0, 0)칸에 있는 모든 픽셀들의 pos 값은 pos.x = 0, pos.y = 0 입니다.
(1, 0)칸에 있는 모든 픽셀들의 pos 값은 pox.x = 1, pox.y = 0 입니다.
칸에 포함된 동일한 픽셀들은 pos 값을 동일하게 가져 가게 됩니다.
오케이,
그러면 이 pos 값을 가지고 random 함수의 첫번째 인자로 사용하게 되면,
random 함수의 리턴값은 위에서 나눈 칸마다 동일하게 되겠네요 !
i.uv *= 10;
float2 ipos = floor(i.uv);
float2 fpos = frac(i.uv);
float3 color = float3(1, 0, 0);
if (random(ipos) > 0.5)
{
color *= Line(fpos, 0.1, 0.05, true);
}
else {
color *= Line(fpos, 0.1, 0.05, false);
}
return float4(color, 1.0);
random 함수에 floor(i.uv)를 적용한 값을 넣어 줘서 각 칸마다 동일한 확률값을 가져옵니다.
확률값은 0.5로 되어있는데 위 값을 변경하여,
y=x 라인과, y=-x+1 라인이 조화롭게 나오는지 확인해보세요~
전체 소스 입니다.
Shader "SimonLee/Shader27Unlit"
{
Properties
{
}
SubShader
{
Tags { "RenderType" = "Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#define PI 3.14159265359
#define PI2 6.28318530718
#include "UnityCG.cginc"
struct v2f
{
float4 vertex : SV_POSITION;
float4 screenPos: TEXCOORD2;
float4 position: TEXCOORD1;
float2 uv: TEXCOORD0;
};
v2f vert(appdata_base v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.screenPos = ComputeScreenPos(o.vertex);
o.position = v.vertex;
o.uv = v.texcoord;
return o;
}
float random(float2 pt) {
const float a = 12.9898;
const float b = 78.233;
const float c = 43758.543123;
return frac(sin(dot(pt, float2(a, b))) * c);
}
float random(float2 pt, float seed) {
const float a = 12.9898;
const float b = 78.233;
const float c = 543758.543123;
return frac(sin(dot(pt, float2(a, b)) * seed) * c);
}
float Line(float2 st, float thick, float blur, bool reserve)
{
if (reserve)
{
st.x = -st.x + 1;
}
return smoothstep(st.x - thick - blur, st.x - thick + blur, st.y) -
smoothstep(st.x + thick - blur, st.x + thick + blur, st.y);
}
fixed4 frag(v2f i) : SV_Target
{
i.uv *= 10;
float2 ipos = floor(i.uv);
float2 fpos = frac(i.uv);
float3 color = float3(1, 0, 0);
if (random(ipos) > 0.5)
{
color *= Line(fpos, 0.1, 0.05, true);
}
else {
color *= Line(fpos, 0.1, 0.05, false);
}
return float4(color, 1.0);
}
ENDCG
}
}
}
위 예제는 ShaderBook에서 참조했습니다.
The Book of Shaders
Gentle step-by-step guide through the abstract and complex universe of Fragment Shaders.
thebookofshaders.com
'Shader CG' 카테고리의 다른 글
2.5 Gradient Noise (0) | 2023.08.17 |
---|---|
2.4 Noise 함수 사용해보기 (0) | 2023.08.12 |
2.2 Noise 모자이크 효과 (0) | 2023.08.09 |
2.1 Noise TV 화면 만들어보기 (0) | 2023.08.06 |
1.6 도형 - 라인 그려보기 (0) | 2023.07.20 |